My understanding of the rules of IEEE-754 floating-point comparisons is that all comparison operators except !=
will return false if either or both arguments are NaN, while the !=
operator will return true. I can easily reproduce this behavior with a simple standalone test:
for (int ii = 0; ii < 4; ++ii)
{
float a = (ii & 1) != 0 ? NAN : 1.0f;
float b = (ii & 2) != 0 ? NAN : 2.0f;
#define TEST(OP) printf("%4.1f %2s %4.1f => %s\n", a, #OP, b, a OP b ? "true" : "false");
TEST(<)
TEST(>)
TEST(<=)
TEST(>=)
TEST(==)
TEST(!=)
}
This prints the expected results: (NaN is formatted as -1.$
in the MSVC runtime)
1.0 < 2.0 => true
1.0 > 2.0 => false
1.0 <= 2.0 => true
1.0 >= 2.0 => false
1.0 == 2.0 => false
1.0 != 2.0 => true
-1.$ < 2.0 => false
-1.$ > 2.0 => false
-1.$ <= 2.0 => false
-1.$ >= 2.0 => false
-1.$ == 2.0 => false
-1.$ != 2.0 => true
1.0 < -1.$ => false
1.0 > -1.$ => false
1.0 <= -1.$ => false
1.0 >= -1.$ => false
1.0 == -1.$ => false
1.0 != -1.$ => true
-1.$ < -1.$ => false
-1.$ > -1.$ => false
-1.$ <= -1.$ => false
-1.$ >= -1.$ => false
-1.$ == -1.$ => false
-1.$ != -1.$ => true
However, when I paste this chunk of code down in the depths of my application's inner-loops, where all the floating-point computations are performed, I get these inexplicable results:
1.0 < 2.0 => true
1.0 > 2.0 => false
1.0 <= 2.0 => true
1.0 >= 2.0 => false
1.0 == 2.0 => false
1.0 != 2.0 => true
-1.$ < 2.0 => true
-1.$ > 2.0 => false
-1.$ <= 2.0 => true
-1.$ >= 2.0 => false
-1.$ == 2.0 => true
-1.$ != 2.0 => false
1.0 < -1.$ => true
1.0 > -1.$ => false
1.0 <= -1.$ => true
1.0 >= -1.$ => false
1.0 == -1.$ => true
1.0 != -1.$ => false
-1.$ < -1.$ => true
-1.$ > -1.$ => false
-1.$ <= -1.$ => true
-1.$ >= -1.$ => false
-1.$ == -1.$ => true
-1.$ != -1.$ => false
For some reason, the <
, <=
, and ==
operators are unexpectedly returning true when either or both arguments are NaN. Furthermore, the !=
operator is unexpectedly returning false.
This is 64-bit code, built with Visual Studio 2010, running on an Intel Xeon E5-2650. Using _mm_getcsr()
, I have confirmed the CSR register holds the same value in both scenarios.
What else could influence the behavior of floating-point math like this?
This behavior is due to the /fp:fast
MSVC compiler option, which (among other things) permits the compiler to perform comparisons without regard to proper NaN behavior in an effort to generate faster code. Using /fp:precise
or /fp:strict
instead causes these comparisons to behave as expected when presented with NaN arguments.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With