2015-02-06 56 views
5

我試圖計算雙打機器精度值和++漂浮在C作爲作業的一部分。我在Windows 7中,64位使用Cygwin,這裏是代碼:機器最小精度差異

#include <iostream> 

int main() { 
    double epsilon = 1; 
    while(1 + epsilon > 1) 
     epsilon = epsilon/2; 
    epsilon = 2*epsilon; 

    std::cout << epsilon << std::endl; 

    float epsilon_f = 1; 
    while(1 + epsilon_f > 1) 
     epsilon_f = epsilon_f/2; 
    epsilon_f = 2*epsilon_f; 

    std::cout << epsilon_f << std::endl; 

    return 1; 
} 

當我運行代碼,我收到1.0842e-019的兩個值。我查了一下,應該得到雙倍的2.22e-16和浮點值的1.19e-07。當我在Macbook上運行確切相同的代碼時,代碼將返回正確的值。什麼可能導致我的Windows機器上的差異?

+1

嘗試改變-mfpmath上交所或387,並確保兩者都在64位模式與-m64。 cygwin可能會默認與macbook不同。此外-fno-快速數學 – 2015-02-06 02:14:52

+0

如果你還在身邊,如果你發現我的答案有幫助,請標記爲接受的 - 這樣一來,其他人也不會在這個問題絆倒後,認爲它仍然需要回答。此外,如果答案沒有幫助,請隨時索取更多信息。 – 2015-02-13 23:35:20

回答

2

The CPU's floating-point registers typically contain 80 bits,它看起來像Cygwin編譯器選擇完全在寄存器中執行循環計算(只打印結果時將結果截斷爲32/64位)。

@Potatoswatter指出,這對於編譯器來說是完全合法的,而且你的程序實際上展現出未定義的行爲,因爲它假定是精度限制。由於有不確定的行爲,編譯器可以選擇你的程序轉換成任何它想做(其中包括一個刪除所有的文件,但是這還好不是一個通用的解決方案...)

附:歡迎來到StackOverflow,對於一個問題的讚揚(如果您閱讀了答案中的概念),可能會讓您更多地瞭解處理器架構和編譯器,而不是您班級中的其他人! :-)

+1

...更重要的是,編譯器允許這樣做。 C和C++根本不會限制中間結果的精度,甚至不會限制某些寄存器的精度。所以,循環不保證終止,程序有未定義的行爲。一種解決方案是使用'volatile epsilon_f'。 – Potatoswatter 2015-02-06 02:18:07

+0

@Patatoswatter:極好的一點! – 2015-02-06 02:18:37

+0

...但是'volatile'只是一個半瓶,它實際上會阻止靜態分析器找到無限循環,但不能保證任何單精度計算。 – Potatoswatter 2015-02-06 02:24:56