2014-01-28 116 views
2

我有下面的代碼是展示一些非常奇怪的行爲。有沒有人有任何想法爲什麼。C++比較函數結果

#include <iostream> 

long global = 20001; 

double foo() {return global/1000.0;} 

int main(int,char**) { 
    if (foo() == foo()) { 
    std::cout << "true\n"; 
    } else { 
    std::cout << "false\n"; 
    } 

    return 0; 
} 

爲函數返回相同的結果每次而是打印假這應該打印正確;

這是在Solaris 10上使用G ++ 我不知道該操作系統的事,但我還沒有機會去嘗試不同的OS

+0

試試這個: flost epsilon = 0.001f; if(foo() - foo()ε .... – AdamF

+1

我編譯你的代碼並收到'true'的響應。我使用gcc 4.6.3運行Ubuntu 12.04。它看起來像操作系統可能很重要。 – Kevin

+0

我在Fedora上用g ++得到'true' – Octopus

回答

3

操作系統可能並不重要,但是編譯器和 架構做。在Intel上,通常的做法是在浮點寄存器中返回浮點數值 ,該浮點寄存器具有64位的精度(而不是雙精度值的53)。當然,編譯器會直接將該算術運算寫入該寄存器中,因此您最終返回的值爲64位,精度爲 。

當然,當編譯器生成的代碼來調用一個函數, 它不能在寄存器中保留值,因爲函數可能 使用該註冊。所以它會讓它記憶。作爲雙位與 56位。 ==運算符將第一次調用中的這個56位值與第二次調用中的64位值進行比較,發現他們不相等。

我可能會補充說,如果編譯器內聯函數,問題可能會消失。

根據標準,所有這些都是完全合法的。

+0

聽起來很合理,有沒有什麼辦法可以在不在本地存儲變量的情況下進行比較工作?這是從一個更大的函數中獲取的代碼,其中將值存儲在本地中並不是一個真正的選項 –

+1

-ffloat-store似乎通過防止寄存器上發生浮點比較來修復它。謝謝你,先生是個天才 –

1

有可能與雙打不是評估一個問題建到始終完全相同的值(基本上舍入錯誤)。

如果你要改變你的函數返回整數,你可能會有預期的行爲。

非常相似,這樣的問題: Deals with comparing floats

試試這個:

#include <iostream> 
#include <limits> 

long global = 20001; 
double epsilon = std::numeric_limits::epsilon<double>(); 

double foo() {return global/1000.0;} 

int main(int,char**) { 
    if (foo() - foo() > epsilon) { 
    std::cout << "true\n"; 
    } else { 
    std::cout << "false\n"; 
    } 

    return 0; 
} 
+0

除了每次都會將_do_計算爲相同的值。這個問題是英特爾在寄存器中擴展精度的一個副作用。 –

+0

啊。我不知道。所以這是一個唯一的問題? – Jmc

+1

今天,可能。在過去,我認爲摩托羅拉芯片也使用了擴展精度,因此可能會顯示相同的問題。 –