Comparing floating numbers is hard. Only yesterday, I've posted this question
My solution:
Public Function DblSafeCompare(ByVal Value1 As Variant, ByVal Value2 As Variant) As Boolean
'Compares two variants, dates and floats are compared at high accuracy
Const AccuracyLevel As Double = 0.00000001
'We accept an error of 0.000001% of the value
Const AccuracyLevelSingle As Single = 0.0001
'We accept an error of 0.0001 on singles
If VarType(Value1) <> VarType(Value2) Then Exit Function
Select Case VarType(Value1)
Case vbSingle
DblSafeCompare = Abs(Value1 - Value2) <= (AccuracyLevelSingle * Abs(Value1))
Case vbDouble
DblSafeCompare = Abs(Value1 - Value2) <= (AccuracyLevel * Abs(Value1))
Case vbDate
DblSafeCompare = Abs(CDbl(Value1) - CDbl(Value2)) <= (AccuracyLevel * Abs(CDbl(Value1)))
Case vbNull
DblSafeCompare = True
Case Else
DblSafeCompare = Value1 = Value2
End Select
End Function
Note that the AccuracyLevel (epsilon) could be set to a smaller value, and I'm using the same value for singles and doubles, but it did well for my purposes.
I'm using a relative epsilon, but multiplying it with the first, and not the largest value, since if there's a significant difference the comparison will fail anyway.
Note that I'm using <=
and not <
since else DblSafeCompare(cdbl(0) ,cdbl(0))
would fail
Note that this function checks for type equality, so comparing integers to longs, doubles to singles, etc. all fails. Comparing Null to Null passes, however.
Implement it:
?DblSafeCompare(cdbl(0.33) + cdbl(0.50) ,cdbl(0.83))
?DblSafeCompare(cdbl(0.331) + cdbl(0.50) ,cdbl(0.83))