2017-02-08 91 views
4

爲什麼這兩個函數的返回值是不同的?奇怪的cbrt()在linux中的結果C

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 

int main() { 
    double nb = 56623104; 
    double v1 = cbrt(nb); 
    printf("v1 -> %.15f\n",v1); 

    double v2 = cbrt((double) 56623104); 
    printf("v2 -> %.15f\n",v2); 
} 

彙編:

GCC toto.c -o託託-lm & & ./toto

結果:

V1 - > 384.000000000000057
v2 - > 384.000000000000000

+2

爲了可靠性,在源或目標文件('toto.c')之後放置庫('-lm')。如果你省略'-lm'選項會發生什麼?它應該無法鏈接,但是......你看過彙編程序了嗎?編譯器是否會評估其中一個函數調用,並在運行時對其中一個進行評估? –

+0

如果您使用任何可選級別(01,O2,O3或Ofast),結果將相同。我已經消除了它,我明白它爲什麼這樣做。現在我試圖解釋爲什麼編譯器會這麼做⊙﹏☉ – Anty

+0

你用'#undef cbrt'獲得相同的行爲嗎? –

回答

3

恭喜,這是一個編譯器錯誤。編譯器通過提前評估cbrt調用之一來優化代碼,不幸的是,編譯器的版本cbrt與您在libm中的版本不同。您還會注意到,傳遞-O2會導致v2結果「錯誤」(即使數學上是正確的)。

我覈實,我的系統中存在的bug

CC(Debian的6.3.0-5)6.3.0 20170124

此錯誤,應當報編譯器開發人員(https://gcc.gnu.org/bugs/) ,但首先搜索bug庫是個好主意。

+0

我確認了CentOS 7.3(cc(GCC)4.8.5 20150623(Red Hat 4.8.5-11))的相同行爲,包括優化效果。我還發現'-fexcess-precision = standard'不會影響結果。 –