Almost Equal Floating Point Numbers
March 25th, 2008
Anyone who’s been writing code for any length of time knows how painful it can be to compare floating point numbers ’cause they’re mere approximations of their true value. For that reason a function to compare floating point values to a specific level of precision is needed.
Don’t understand myself wrong. Usually when comparing floats you round them in a specified way and then compare them.
Here the aim is different: Comparison of the values that were passed and find out if there are almost equal.
Common way with rounding is:
bool CompareFloats(double dVal1, double dVal2, double dTolerance) { return abs(dVal1 - dVal2) < dTolerance; }
If you wish to have a tolerance of 0.01, then use a constant of some kind. The pow function is also efficient for different levels of decimal precision: pow(0.1, nPrecision);
—
The following function does comparison of two double values and returns if they’re almost equal. The precision parameter specifies what relative error we are willing to tolerate.
bool AlmostEqualFloats(double dVal1, double dVal2, int iPrecision) { char sVal1[255]; char sVal2[255]; nPrecision = __max(__min(16, iPrecision), 0); sprintf_s(sVal1, sizeof(sVal1), "%.*lf", nPrecision, iVal1); sprintf_s(sVal2, sizeof(sVal2), "%.*lf", nPrecision, iVal2); bool bResult = (strcmp(sVal1, sVal2) == 0); return bResult; }
There’s not much to tell about it. The major disadvantage is the usage of STL’s sprintf_s and strcmp, or better said, the manipulation of strings. Be aware that using strings is somewhat inefficient in a function like that.
Finally, here a version of the function that doesn’t do any string manipulation at all.
bool AlmostEqualFloats(double dVal1, double dVal2, int iPrecision) { iPrecision = __max(__min(16, iPrecision), 0); double dTmp = 1.0; for (int i = 1; i <= iPrecision; i++) { dTmp *= 0.1; } bool bResult = (((nVal2 - dTmp) < nVal1) && (nVal1 < (nVal2 + dTmp))); return bResult; }
When watching this function work in the debugger, you might notice that performing any math of the dTmp value caused it to become impure. The very last digit of the mantissa was some random value. This almost guarantees that at some point, the value will be such that it returns an incorrect result.
To make it clear, here’s a version of the function that accepts a direct value for dTmp in the form of an appropriate value. For instance, if you want a precision of 3, you would pass in 0.001.
bool AlmostEqualFloats(double dVal1, double dVal2, double dTmp) { bool bResult = (((dVal2 - dTmp) < dVal1) && (dVal1 < (dVal2 + dTmp))); return bResult; }
As a conclusion I can say that it is (hardly) impossible to reliably compare two floating point numbers for equality.
Without great performance effort for math calculations can’t write a function that always returns the correct value when comparing floating point numbers. Typically, when people say “almost”, it involves some kind of relativity. For example, 1000000001 is almost 1000000000 and .999999999 is almost 1.





