如果任一参数为 NaN,什么会导致 C/C++ <、<= 和 == 运算符返回 true?

What would cause the C/C++ <, <=, and == operators to return true if either argument is NaN?

本文关键字:lt true 返回 运算符 C++ NaN 参数 任一 什么 如果      更新时间:2023-10-16

我对IEEE-754浮点比较规则的理解是,如果参数之一或两个都是NaN,除了!=之外的所有比较运算符将返回false,而!=运算符将返回true。我可以很容易地用一个简单的独立测试重现这个行为:

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 => %sn", a, #OP, b, a OP b ? "true" : "false");
    TEST(<)
    TEST(>)
    TEST(<=)
    TEST(>=)
    TEST(==)
    TEST(!=)
}

打印预期的结果:(NaN在MSVC运行时被格式化为-1.$)

 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

然而,当我将这段代码粘贴到应用程序的内循环深处(所有浮点计算都在这里执行)时,我得到了这些令人费解的结果:

 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

由于某种原因,<<===操作符在其中一个或两个参数都是NaN时意外返回true。此外,!=操作符意外返回false。

这是64位代码,使用Visual Studio 2010构建,运行在Intel Xeon E5-2650上。使用_mm_getcsr(),我已经确认CSR寄存器在两种情况下保持相同的值。

还有什么可以影响像这样的浮点数学行为?

此行为是由于/fp:fast MSVC编译器选项,它(除其他外)允许编译器执行比较,而不考虑适当的NaN行为,以生成更快的代码。使用/fp:precise/fp:strict会使这些比较在使用NaN参数时按照预期的方式进行。