Hacker News new | ask | show | jobs
by exDM69 3369 days ago
Here's my less-than-scientific floating point near-equality test I use.

    bool zero(float x) ( return x*x < FLT_EPSILON; }
    bool equal_float(float a, float b) {
        return (zero(a) && zero(b)) ||   // both are zero
            zero((a-b)*(a-b) / (a*a + b*b)); // or relative error squared is zero
    }
This checks equality to about four decimal digits for 32 bit single precision and seven digits for 64 bit floats. Inf/NaN special values are not considered.

Critique and comments welcome.

1 comments

`FLT_EPSILON` represent the minimum difference between two adjacent floats around 1.0; it should be scaled according to the input argument. E.g. your `equal_float` returns `true` for 2e-6 and 4e-6 which are clearly not the same number.

A better comparison would check for zero somehow like this:

    bool zero(float x) { return std::abs(x) <= std::abs(x)*FLT_EPSILON;  }
Yes, this is by design and it works as intended.

I typically use this with doubles and DBL_EPSILON, which is much much smaller than FLT_EPSILON.

With FLT_EPSILON this roughly equals to "zero" being "less than 0.001". If the zero check is omitted, there's going to be a division by near-zero which will make the results nonsense (and you have to draw the line somewhere). With DBL_EPSILON "zero is less than 0.000000001".

If this is too loose, then `zero(x) = abs(x) < FLT_EPSILON` makes it much stricter (about 1e-7).

This is good enough for my purposes, I don't deal with very small numbers in float and doubles give more than enough precision.

NOTE: I usually use this kind of comparison in testing by comparing known "gold" figures against the results of the code being tested. I don't test accuracy, I test for "in the ballpark" because the stuff I deal with has built-in inaccuracy in the algorithm and numerics.

The version you posted will always return false if I read it correctly.