2017-04-02 63 views
0

我有以下的情況,讓我27,而不是28:轉換雙爲int誤差(1個關)

double d = 0.35; 
int i = 80; 

int ans = (int)(d * i); 

printf("%d", ans); 

但我得到正確的答案,如果我用這個:

int ans = (int)(0.35 * 80); 
printf("%d", ans); 

或:

double ans = d * i; 
printf("%d", (int) ans); 

有人可以解釋爲什麼第一種情況是1個關和其他人的工作?

我做了一些研究和人說雙存儲數字,如28 27.999 ...,但我很困惑,在什麼情況下,這會發生。Britain

謝謝!

+0

你的問題是關於C,而不是C++。至於問題本身,我無法重現你的問題。在gcc(Ubuntu 4.8.1-2ubuntu1〜12.04)上的所有三種情況下,我得到了28分。 – DyZ

+2

[我嘗試在ideone中,它返回28](https://ideone.com/6J4yMm)。你使用的是什麼編譯器和平臺? – AntonH

+3

有幫助的閱讀:[每個計算機科學家應該知道的關於浮點運算的內容](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) – user4581301

回答

3

0.35的值沒有精確的二進制浮點表示。因此,在使用基於IEEE 754的浮點支持的典型平臺上,您的double d = 0.35;根本不是0.35,而是諸如0.34999999999999998之類的值 - 在此情況下的值恰好是,比原始的小。其餘的如下:乘法產生小於28,它會被(int)截斷爲27。故事結局。

如果有人從這個例子中得到28這可能意味着他們的編譯器使用不同的浮點評價模型,其中原始0.35可能代表兩種正是或某個值略微更大0.35(說,0.35000000000012或類似的東西)。優化計算並在編譯時執行它們的編譯器也屬於該類別。

的差異

之間

int ans = (int)(d * i); 
printf("%d", ans); 
double ans = d * i; 
printf("%d", (int) ans); 
可能很容易由編譯器字面上存儲在第二情況下的 double可變 ans中間結果而引起的。

實際乘法可能在CPU的高精度浮點寄存器中執行(其精度高於double)。在第一種情況下,結果直接存儲到int中。在第二種情況下,它首先轉換爲較低精度的double,然後double轉換爲int。這種額外的中間轉換爲double可以輕鬆改變結果。

+0

你的回答並不能解釋爲什麼'int ans =(int)(d * i)'與'double ans = d * i不同; INT(ANS)'。在後一種情況下,「d」不是被隱含地提升爲「雙」嗎? – DyZ

+0

因此,如果ans = 0.35 * 80,則28.000將被存儲到ans而不是27.999 ...對嗎? – Rig

+0

@Rig:沒有人知道將存儲什麼。這取決於您的編譯器在計算此表達式時需要採取什麼方法。編譯它並查看機器代碼,看看你的編譯器決定做什麼 - 這是知道的唯一方法。但不要把它當作絕對的事實,因爲明天你的編譯器可能會開始有不同的表現。 – AnT