2014-05-13 18 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