This nice paper on floating point comparison clearly explains why checking absolute difference or relative difference against a threshold doesn’t work in all situations. The problem with relative difference is when values are close to 0, if you do fabs(a-b)/( (fabs(a)>fabs(b)) ? a : b ).

The solution is to directly compare the “integer representation” of the floating point value, i.e. the actual bits of the float.

// Usable AlmostEqual function
bool AlmostEqual2sComplement(float A, float B, int maxUlps)
{
// Make sure maxUlps is non-negative and small enough that the
// default NAN won't compare as equal to anything.
assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);
int aInt = *(int*)&A;
// Make aInt lexicographically ordered as a twos-complement int
if (aInt < 0)
aInt = 0x80000000 - aInt;
// Make bInt lexicographically ordered as a twos-complement int
int bInt = *(int*)&B;
if (bInt < 0)
bInt = 0x80000000 - bInt;
int intDiff = abs(aInt - bInt);
if (intDiff <= maxUlps)
return true;
return false;
}

ULPs stands for Units in the Last Place.

Advertisements