What I’m going to discuss isn’t anything specific to Inventor but is a general issue to be aware of when working with computers and floating point numbers. The thing you need to understand is that floating point numbers are not always exact. They’re very very close to the expected number and close enough for computations but you can run into problems when comparing numbers. Below is a VBA sample that illustrates the problem. I want to emphasize that the issue is not limited to VBA but can be seen with any programming language.
Public Sub CompareNumbers()
Dim val1 As Double
val1 = 0.1 + 0.1 + 0.1
Dim val2 As Double
val2 = 0.3
Debug.Print "val1 = " & CStr(val1) & ", val2 = " & CStr(val2)
If val1 = val2 Then
Debug.Print "Values match"
Else
Debug.Print "Values do not match"
End If
Debug.Print "Difference = " & val1 – val2
End Sub
When I run the program above I get the following results in the Immediate window.
val1 = 0.3, val2 = 0.3
Values do not match
Difference = 5.55111512312578E-17
The first line is what you would expect but the second and third lines are a bit of a surprise. You would expect the two variables to have the same value but the comparison shows that they are not equal and the last line shows by how much they are different; 0.0000000000000000555111512. That value is close enough to being equal that in almost all cases you don’t need to care about the difference but when using the “=” comparison they must match exactly.
More than you ever wanted to know about why this happens can be found at http://en.wikipedia.org/wiki/Floating_point. A simpler explanation can be found here: http://floating-point-gui.de/
The Solution
The solution to this problem is to not ever expect floating point numbers to be exactly equal but instead allow for them to be equal within a tolerance. This is described in one of the links I provided above (http://floating-point-gui.de/errors/comparison/). Here’s my simple solution which according to the link is not the right way to do it, but I think in my case it works because I know the range of values that I’m working with. Anyone working with Inventor is limited to sizes and tolerances that Inventor can handle so we know we’re not working with sizes in light years or nanometers. When comparing two points, Inventor considers them to be the same if they’re within 0.0000000001 centimeters.
The code below is a modified version of the previous Sub that uses a function to do the value comparison.
Public Sub CompareNumbers2()
Dim val1 As Double
val1 = 0.1 + 0.1 + 0.1
Dim val2 As Double
val2 = 0.3
Debug.Print "val1 = " & CStr(val1) & ", val2 = " & CStr(val2)
If IsEqual(val1, val2) Then
Debug.Print "Values match"
Else
Debug.Print "Values do not match"
End If
End Sub
Below is the IsEqual function that compares to the two values within the specified tolerance.
Public Function IsEqual(Value1 As Double, Value2 As Double, _
Optional Tolerance As Double = 0.000000000001) As Boolean
If Abs(Value1 - Value2) < Tolerance Then
IsEqual = True
Else
IsEqual = False
End If
End Function
Below is a more elaborate version of the IsEqual function that supports various types of comparisons.
' Compares two numbers to see if they meet the comparison condition
' within the specified tolerance.
' Valid comparison operators are, "=" "<", ">", "<=", and ">=".
Public Function NumbersCompare(Value1 As Double, Value2 As Double, _
operator As String, _
Optional Tolerance As Double = 0.000000000001) As Boolean
Dim difference As Double
difference = Abs(Value1 - Value2)
Dim comparison As String
comparison = ""
Dim equals As Boolean
equals = False
If Len(operator) = 2 Then
' Determine if the operator is greater or less than.
If Mid(operator, 1, 1) = ">" Then
comparison = ">"
ElseIf Mid(operator, 1, 1) = "<" Then
comparison = "<"
Else
MsgBox "Bad comparison operator: " & operator
NumbersCompare = False
Exit Function
End If
' Determine if equals to is specified.
If Mid(operator, 2, 1) = "=" Then
equals = True
Else
MsgBox "Bad comparison operator: " & operator
NumbersCompare = False
Exit Function
End If
ElseIf Len(operator) = 1 Then
' Determine if the operator is greater than,
' less than, or equals to.
If operator = ">" Then
comparison = ">"
ElseIf operator = "<" Then
comparison = "<"
ElseIf operator = "=" Then
equals = True
Else
MsgBox "Bad comparison operator: " & operator
NumbersCompare = False
Exit Function
End If
Else
MsgBox "Bad comparison operator: " & comparison
NumbersCompare = False
Exit Function
End If
' Do the actual comparisons.
If operator = ">" Then
' Check if the value is greater than, using the tolerance.
If Value1 + Tolerance > Value2 Then
NumbersCompare = True
Exit Function
Else
NumbersCompare = False
End If
ElseIf operator = "<" Then
' Check if the value is less than, using the tolerance.
If Value1 - Tolerance < Value2 Then
NumbersCompare = True
Exit Function
Else
NumbersCompare = False
End If
End If
' Check if the numbers are equal, within the tolerance.
If equals Then
If difference <= Tolerance Then
NumbersCompare = True
Exit Function
Else
NumbersCompare = False
End If
End If
End Function
Here’s an example of the function above in use.
Public Sub CompareNumbers3()
Dim val1 As Double
val1 = 0.1 + 0.1 + 0.1
Dim val2 As Double
val2 = 0.3
Debug.Print "val1 = " & CStr(val1) & ", val2 = " & CStr(val2)
If NumbersCompare(val1, val2, "<=") Then
Debug.Print "Values compare"
Else
Debug.Print "Values do not compare"
End If
End Sub
This is only a problem when working with floating point numbers. Integers and strings are always exact and exact comparisons will work as expected.
-Brian