2013-09-05 152 views
2

我想這是一個相當基本的問題,但我不知道爲什麼這兩個代碼給出不同的結果。 Pentium是否處理變量Divider與中間值(256.0 /(double)k)不同?這兩個簡單的代碼爲什麼會給出不同的結果?

int j=64, k=20; 
double x, y, Divider; 

Divider = 256.0/(double)k; 
x = (double)j/Divider - 5.0; 
y = (double)j/(256.0/(double)k) - 5.0; 

結果: X = -2.77555756156289E-16 Y = 0.0

作爲參考,我使用Embarcadero公司XE3 C++生成器,其給出作爲生成器相同的結果6.我使用的默認編譯器設置。

+0

一些編譯器保證他們總是將x和y的計算編譯爲等效的指令。有些編譯器保證它們不會生成相同的指令,因爲將'double'類型的中間計算分配給'double'左值具有影響。有些編譯器甚至不知道有什麼區別。如果沒有關於編譯器的信息,很難說更多,但查找'FLT_EVAL_METHOD'(在C99中引入)以獲取更多信息。 –

回答

2

問題是,當您不使用SSE指令時,編譯器可能會選擇使用本機387浮點單位進行中間計算,該單位將執行所有80位值的計算。

在計算x時,通過將中間值存儲在Divisor中,強制中間值被截斷爲64位。然後下一個分部使用一個已經舍入的除數;由於分工的精度足夠高,所以結果與5.0略有不同。

y的計算中,除法以80位精度完成,因此結果更接近5.0(足夠接近以至截斷爲64位使其爲0)。

如果您使用SSE(只有64位寄存器),您還可以獲得兩個0值,否則強制編譯器以64位精度執行所有計算。

0

也許是優化器。在第二個

y = (double)j/(256.0/(double)k) 

是相同的數學上

y = (double)j * (double)k/256.0 

此只做一次除法(巧合乾淨劃分),並且受以下的舍入誤差。對於x它被迫做兩個師。

+0

括號強制首先執行「256.0 /(double)k」。從其他角度來看,由於'j'和'256'是2的冪,並且如果編譯器忽略了括號,'j/256'將被精確計算。 –

+0

是的,但我已經讀過一些英特爾編譯器會默認使用'-fp model fast = 1',這可能會導致不太精確的結果。編譯器不會忽略括號,但它可能知道足以將「j」和「k」相乘。海報並沒有說他使用了什麼編譯器,所以這只是一個猜測。 – dseiple

+0

我正在使用Embarcadero的C++ Builder –

相關問題