c++floating-pointfloating-accuracydouble-precision

How to correctly and standardly compare floats?


Every time I start a new project and when I need to compare some float or double variables I write the code like this one:

if (fabs(prev.min[i] - cur->min[i]) < 0.000001 &&
    fabs(prev.max[i] - cur->max[i]) < 0.000001) {
        continue;
}

Then I want to get rid of these magic variables 0.000001(and 0.00000000001 for double) and fabs, so I write an inline function and some defines:

#define FLOAT_TOL 0.000001

So I wonder if there is any standard way of doing this? May be some standard header file? It would be also nice to have float and double limits(min and max values)


Solution

  • Thanks for your answers, they helped me a lot. I've read these materials:first and second

    The answer is to use my own function for relative comparison:

    bool areEqualRel(float a, float b, float epsilon) {
        return (fabs(a - b) <= epsilon * std::max(fabs(a), fabs(b)));
    }
    

    This is the most suitable solution for my needs. However I've wrote some tests and other comparison methods. I hope this will be useful for somebody. areEqualRel passes these tests, others don't.

    #include <iostream>
    #include <limits>
    #include <algorithm>
    
    using std::cout;
    using std::max;
    
    bool areEqualAbs(float a, float b, float epsilon) {
        return (fabs(a - b) <= epsilon);
    }
    
    bool areEqual(float a, float b, float epsilon) {
        return (fabs(a - b) <= epsilon * std::max(1.0f, std::max(a, b)));
    }
    
    bool areEqualRel(float a, float b, float epsilon) {
        return (fabs(a - b) <= epsilon * std::max(fabs(a), fabs(b)));
    }
    
    int main(int argc, char *argv[])
    {
        cout << "minimum: " << FLT_MIN      << "\n";
        cout << "maximum: " << FLT_MAX      << "\n";
        cout << "epsilon: " << FLT_EPSILON  << "\n";
    
        float a = 0.0000001f;
        float b = 0.0000002f;
        if (areEqualRel(a, b, FLT_EPSILON)) {
            cout << "are equal a: " << a << " b: " << b << "\n";
        }
        a = 1000001.f;
        b = 1000002.f;
        if (areEqualRel(a, b, FLT_EPSILON)) {
            cout << "are equal a: " << a << " b: " << b << "\n";
        }
    }