2014-05-13 20 views
42

我对IEEE-754浮点比较规则的理解是,除!=之外的所有比较运算符将返回false,如果其中一个或两个参数都是NaN,而!=运算符将返回true。我可以很容易地重现此问题有一个简单的独立测试:如果任一参数是NaN,会导致C/C++ <,<=和==运算符返回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 => %s\n", 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。

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

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

+12

我讨厌只有迪尔伯特的报价,但“这里有镍,孩子。让自己更好的编译器“ –

+2

你确定他们传统的准C89模式被广告为符合IEEE-754标准?无论如何,你有快速数学或一些这样的启用? – Deduplicator

+1

好像你的编译器正在抛出规范的某些部分以提高性能...... – Synxis

回答

52

此行为归因于/fp:fast MSVC编译器选项,该选项允许编译器执行比较,而不考虑正确的NaN行为,以便生成更快的代码。使用/fp:precise/fp:strict而不是使用NaN参数导致这些比较的行为与预期相同。

+0

+1 Nice find! – Mysticial

+14

+1并添加链接。请记住,您也可以使用'#pragma float_control'为特定的代码段设置此行为。 –

+1

奇怪的是,'/ fp:fast'选项只会在更大的应用程序的上下文中触发这种无效的NaN行为。当我在独立的'main()'函数中将'/ fp:fast'应用于此代码时,它的行为正确。 – Sean