“-Weverything” yielding “Comparing floating point with == or != is unsafe”

后端 未结 5 1892
无人及你
无人及你 2020-12-10 00:58

I have a string that I convert to a double like this:

double d = [string doubleValue];

The documentation for doubleValue tells

相关标签:
5条回答
  • 2020-12-10 01:18

    Floats should not be compared with == or != due to inaccuracy of the float type, which could result in unexpected errors when using these operators. You should test if the floats lie within a distance of each other instead ( called "Epsilon" most of the time ).

    It could look like this:

    const float EPSILON = 1.0f; // use a really small number instead of this
    
    bool closeEnough( float f1, float f2)
    {
        return fabs(f1-f2)<EPSILON; 
        // test if the floats are so close together that they can be considered equal
    }
    
    0 讨论(0)
  • 2020-12-10 01:23

    If you are sure about your comparison and you want tell it to clang, surround your code with:

    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wfloat-equal"
    /* My code triggering the warnings */
    #pragma clang diagnostic pop
    
    0 讨论(0)
  • 2020-12-10 01:32

    In this case, try using >= and <=.

    0 讨论(0)
  • 2020-12-10 01:36

    You do not need to worry about this warning. It is nonsense in a lot of cases, including yours.

    The documentation of doubleValue does not say that it returns something close enough to HUGE_VAL or -HUGE_VAL on overflow. It says that it returns exactly these values in case of overflow.

    In other words, the value returned by the method in case of overflow compares == to HUGE_VAL or -HUGE_VAL.

    Why does the warning exist in the first place?

    Consider the example 0.3 + 0.4 == 0.7. This example evaluates to false. People, including the authors of the warning you have met, think that floating-point == is inaccurate, and that the unexpected result comes from this inaccuracy.

    They are all wrong.

    Floating-point addition is “inaccurate”, for some sense of inaccurate: it returns the nearest representable floating-point number for the operation you have requested. In the example above, conversions (from decimal to floating-point) and floating-point addition are the causes of the strange behavior.

    Floating-point equality, on the other hand, works pretty much exactly as it does for other discrete types. Floating-point equality is exact: except for minor exceptions (the NaN value and the case of +0. and -0.), equality evaluates to true if and only if the two floating-point numbers under consideration have the same representation.

    You don't need an epsilon to test if two floating-point values are equal. And, as Dewar says in substance, the warning in the example 0.3 + 0.4 == 0.7 should be on +, not on ==, for the warning to make sense.

    Lastly, comparing to within an epsilon means that values that aren't equal will look equal, which is not appropriate for all algorithms.

    0 讨论(0)
  • 2020-12-10 01:43

    Probably not necessary for this very simple use case, but here is an example of how you would account for the potential discrepancy if you were trying check if a number is equal to -1:

    #include <float.h>
    #include <math.h>
    
    int main(void) {
      float sales = -1;
    
      // basically if sales == -1
      if (fabs(1 + sales) < FLT_EPSILON) {
        return 0;
      }
    }
    
    0 讨论(0)
提交回复
热议问题