Software is Crap

Floating point comparisons, by someone who doesn’t understand math.


A link to the following page was posted on Slashdot today:

Although the author asks Slashdot for comments (urgh) I’m not willing to comment there as whatever I will say will be lost in the noise. (yep, there are some clever people who post to Slashdot, it’s just hard to see them behind all the trolls and idiots). I would just send the author an email but they have for some reason neglected to include their name and contact details anywhere.

Anywya, the assertion is made that you shouldn’t compare floating point values using an epsilon, specifically:

if( Math.abs(a-b) < 0.00001) // wrong - don't do this

The reasoning however is difficult to follow:

This is a bad way to do it because a fixed epsilon chosen because it “looks small” could actually be way too large when the numbers being compared are very small as well.

Geez. If both numbers are small, then they are in fact close together in value and the above comparison is perfectly valid. It is in fact the whole point of the comparison. You don’t need to take the magnitude of the values into account unless, well, you have a good reason for it. And in general, if the magnitude is significant, you don’t want to be doing an equality comparison anyway. The key is not to have a dynamic epsilon (which is ultimately what the convoluted piece-of-filth code the author then presents ultimately, er, fails to achieve) but rather to have an epsilon value which is meaningful in the context of the comparison (i.e. how much of a difference in value are you willing to tolerate, taking error into account?).

Yes, larger magnitudes have less precision, but that doesn’t necessarily mean you want to widen the range of what is considered equal. Somtimes, exactly what you want in such cases is for the comparison to always fail (unless of course the values are actually identical).

Incidentally if you did want to take magnitude into account, it would probably be much simpler to do something like:

float d = a / b;
if (d > 0.999 && d < 1.001) {
    // near enough to equal

… though of course you may (depending on language and environment, and specifically divide-by-zero behaviour) still need to handle the case of “b” being 0 (most likely by considering the values unequal, unless “a” is also zero).

The point is, consider your needs when doing floating point comparison. It’s true that you’ll rarely want to compare floats for exact equality, but exactly how you test for “inexact equality” is dependent on the situation. Think about what you are trying to achieve, and don’t believe what some monkey’s web page says.