Can we rely on op== to binary-compare floating-poi

2020-02-10 15:02发布

问题:

We all know (right?!) that one should not compare floating-point values by testing for equality (operator==).

But what if I actually want to determine whether two floats a and b are binary equal? If they're not allowed to be NaN (or other "special values"), is this "safe"? Can I rely on operator== to function in this way?

回答1:

(Assuming IEEE-754 representations) almost, but not quite. If you can rule out NaNs, you still need to deal with the fact that +0.0 and -0.0 have different binary encodings, but compare equal (because both are exactly zero).

Of course, C++ doesn't require IEEE-754. So strictly speaking, all bets are off.

If you want to check for (in)equality of encoding, just use memcmp(&a, &b, sizeof a).



回答2:

The accepted answer ignores a very important aspect: extended precision floating point. The CPU may be doing calculations with a bit-size that exceeds your storage size. This will particularly be true if you use float but can also be true of double and other floating point types.

To show the problem, the following assert may actually fail depending on how the compilation was done and how the chip behaves.

  void function( float a )
  {
     float b = a / 0.12345;
     assert( b == (a/0.12345) );
  }

Now, in this reduced example it will likely always pass, but there are many cases where it will not. Simply look at GCC Bug 323 and look at how many defects are marked as duplicates. This extended precision causes problems for many people, and it may also cause problems for you.

If you need a guarantee what you'll need to do is make a comparison function that takes two float parameters and guarantee that the function is never inlined (stored floats are not subject to extended precision). That is, you must ensure those floats are actually stored. There is also a GCC option called "store-float" I believe which forces storage, perhaps it can be used here on your individual function.



回答3:

To make sure a floating point value is not NaN, you can compare it with itself:

double foo;
// do something with foo
if (foo != foo) {
    std::cout << "Halp! Foo is NaN!";
}

I am pretty sure this is guaranteed by the IEEE-754 standard.