2014-02-23 113 views
11

在我的機器上,以下程序的結果對我來說有點奇怪。爲什麼double的值似乎在賦值後被改變?

#include <iostream> 

using namespace std; 

int main(){ 
    double a = 20; 
    double b = 0.020; 
    double c = 1000.0; 

    double d = b * c; 

    if(a < b * c) 
     cout << "a < b * c" << endl; 

    if(a < d) 
     cout << "a < d" << endl; 

    return 0; 
} 

輸出:

$ ./test 
a < b * c 

我知道雙是因爲精度不準確。但我並不認爲這個價值會發生變化,並會導致不一致的比較結果。

如果打印出a < b * c,我確實希望a < d也應該打印出來。但是當我在我的i686服務器上甚至在我的cygwin上運行這個代碼。我可以看到a < b * c,但看不到a < d

此問題已被確認爲與平臺相關。這是由雙重任務的不同指令和執行引起的嗎?

UPDATE

生成的組件:

main: 
.LFB1482: 
    pushl %ebp 
.LCFI0: 
    movl %esp, %ebp 
.LCFI1: 
    subl $56, %esp 
.LCFI2: 
    andl $-16, %esp 
    movl $0, %eax 
    subl %eax, %esp 
    movl $0, -8(%ebp) 
    movl $1077149696, -4(%ebp) 
    movl $1202590843, -16(%ebp) 
    movl $1066695393, -12(%ebp) 
    movl $0, -24(%ebp) 
    movl $1083129856, -20(%ebp) 
    fldl -16(%ebp) 
    fmull -24(%ebp) 
    fstpl -32(%ebp) 
    fldl -16(%ebp) 
    fmull -24(%ebp) 
    fldl -8(%ebp) 
    fxch %st(1) 
    fucompp 
    fnstsw %ax 
    sahf 
    ja .L3 
    jmp .L2 

    //.L3 will call stdout 
+1

也許它是與不斷優化。如果從'std :: cin'中抓住'a','b'和'c',你能顯示程序集還是重現它? –

+0

沒有來自編譯器的錯誤/警告。 – StarPinkER

+0

我可以重現它如果我從std :: cin得到它,我會在稍後發佈它。 @NateKohl – StarPinkER

回答

5

假設:你可以看到80位Intel FPU的影響。

使用定義double d = b * c,數量b * c以80位精度計算,並在存儲到d時舍入到64位。 (a < d)將比較64位a與64位d

OTOH,帶有表達式(a < b * c),在離開FPU之前,您有一個80位算術結果b * ca直接進行比較。因此,b*c結果從未將其精度修改爲保存在64位變量中。

你必須看看生成的指令是肯定的,我期望這將隨編譯器版本和優化器標誌而變化。

+0

見http://stackoverflow.com/q/20869904/420683 – dyp

+0

我想在這裏http://coliru.stacked-crooked.com/a/3022f77c07303e32設置的x87,但它並沒有區別。 x87或SSE沒有輸出。這並不否定你所說的任何話,但我只是好奇我必須設置哪些編譯器標誌才能看到效果。 –

3

我不確定AS3機器是什麼類型的硬件,但是例如,您可以在內部浮點單元使用大於64位浮點數來存儲中間結果的機器中看到此行爲。在x87浮點單元(但不包含SSE)的情況下就是這種情況。

問題是處理器將在bc中加載到浮點寄存器,然後執行乘法並將臨時結果存儲在寄存器中。如果該寄存器大於64位,結果將會與d(或a)不同,後者被計算並存回內存,強制它們爲64位。

這是很多情況下,你需要看看你的彙編代碼,以確定究竟是怎麼回事。您還需要了解硬件在內部如何處理浮點計算。

+0

我認爲你是對的。但是,這是否意味着比較a和中間結果時,中間值不會放到內存中,而是加載到fpu並在那裏進行比較? – StarPinkER

1

在我的Windows機器上用MinGW對代碼進行快速測試可以產生完全相同的結果。然而,真正奇怪的是,如果我將雙打變成浮動,所有東西都應該完美地運行(根本沒有輸出)。但是,如果我將它們更改爲長雙打,則會顯示「a < b * c」和「a < d」。

我的猜測是,也許因爲雙打都應該允許更多的精度,奇怪的事情是怎麼回事相乘的兩個直接的價值,做一個比較時上,與存儲用於以後的結果?這也可以解釋爲什麼最終這個問題會出現很長的雙打,因爲它們需要更多的內存空間。

相關問題