2011-09-28 75 views
3

看看下面的兩個代碼,並告訴我爲什麼答案差異很大。浮點比較給出了不同的結果

#include<stdio.h> 
int main() { 
    float a = 0.9; 
    if(a<0.9) 
     printf("hi"); // This will be the answer 
    else 
     printf("bye"); 
    return 0; 
} 

如果我們改變0.9到0.8,那麼別人的語句印:

#include<stdio.h> 
int main() { 
    float a = 0.8; 
    if(a<0.8) 
     printf("hi"); 
    else 
     printf("bye");//this will be the answer 
    return 0; 
} 

那麼,爲什麼這個輸出改變時,我們只需要改變一個數字?

+2

不要說得這麼富有戲劇性! _just改一個digit_!您在任何地方的任何程序中更改一位數字,輸出會發生變化。 – Shahbaz

+0

另外,也請閱讀我的答案。起初我犯了一個錯誤,並得到-1s,但隨後編輯它,現在它包含一個共同的解決辦法,以您的問題 – Shahbaz

回答

1

你必須知道浮點是如何工作的。

浮點數用2的冪來表示,每個數字用來表示2^-x,其中X是第n個數字。

例如,0.011(二進制)。將2^-2 + 2^-3,這是0.25 + 0.125 = 0.375

現在嘗試表示0.9。你有麻煩了,因爲沒有兩個力量來代表它。以32位和可能的64位機器表示的值將給出比0.9,略小的結果,而對於0.8,結果是精確的並且可以通過兩個冪來表示。

您可以通過打開python提示來嘗試此操作。嘗試輸入一些數字,最後以...99999999結尾。

+1

@wormsparty:'0。8'在單精度浮點數或雙精度浮點數中不能完全表示。 –

+0

當轉換爲二進制時,0.8和0.9都會重複出現。不同之處在於兩種條件的工作方式不同。 –

+0

問題是,0.8被放入一個浮點數,所以它有一些二進制表示可能在一個接近0.8f的數字的32位中。之後,比較是在double上進行的,所以爲了比較它,它將浮點數轉換爲雙精度64位表示,它不再精確地表示0.8,而是其他一些非常接近的數字。它將它與未經轉換的雙倍0.8進行比較。查看下面的答案以獲取更多詳細信息。 – wormsparty

10

此錯誤是由於浮點精度,因爲您將float類型與double值進行比較。嘗試比較它與浮點文字:if(a<0.8f)

我建議你閱讀根據wikipedia article,它詳細解釋了爲什麼你的錯誤發生。

+0

@Constantinius:是的,我跟你解釋ragarding問的問題達成一致,但爲什麼不同樣的事情與發生#包括 int main(){ float a = 0.9; if(a <0.9) printf(「hi」); 其他 的printf( 「再見」); //這將是答案 返回0; } Acording到烏爾答案再見shud是打印的,但它不是......但是,當以0.8 0.9的變化是確定.. –

+0

@Nishant:由於0.9的(不準確)單精度值恰好小於(不準確)的雙精度值,而對於0.8,它更大。 –

0

首先,正如其他人提到的那樣,在使用float s時,請使用像0.8f這樣的值。

另外,浮點數==比較是你想避免的,因爲這個操作在FPU中的精度。什麼總是工作最適合我,是定義保證金,假設1e-6f(或者你需要根據你的應用的精度)和代替本:

if (LHS == RHS) 

你寫:

if (LHS-RHS < MARGIN && RHS-LHS < MARGIN) 

你可以編寫一個函數(如果你是一個C++粉絲)或宏(如果你是ac粉絲(這裏是-1s))爲你做這個。

5

文字0.90.8的類型爲double。由於兩個值都不能完全表示,所以它們實際上將是0.9000000000000000222...0.8000000000000000444...

當存儲在float(單精度)可變a它們將被轉化爲單個和變得更加不精確:0.89999997...0.8000000119...

爲了與文字double的值進行比較,它們被轉換回double,保留了更不準確的值。

正如你可以從上面的數字看,比較產生的0.90.8不同的結果。

這一切都是假設你的平臺有IEEE754浮這是最有可能的情況下。

您可以在www.binaryconvert.com看到數字的單/雙表示。

-1

試試這個:

而不是 「如果(一個< 0.9)」 用比較 「如果(一個< 0.9f)」

1

按照C標準:

6.3。 1.5實際浮動類型

1)當浮動提升爲double或long double或雙倍提高爲long double時,其值不變。 2)當一個雙精度浮點降爲浮點數時,一個長雙精度浮點數被降爲雙精度浮點數或者浮點數,或者以比其語義類型(見6.3.1.8)要求更高的精度和範圍 轉換爲它的語義類型,如果正在轉換的值可以是 ,則表示它是新的類型,它不會改變。如果要轉換的值 處於可以表示的值的範圍內,但不能精確地表示 ,則結果可能是最接近的較高的 或最接近的較低的可表示值,以 實現定義的方式選擇。如果要轉換的值超出 可以表示的值的範圍,則行爲是未定義的。

該標準可以找到here

0

這是由於舍入誤差,看到您正在使用插入一個printf前值,如果:

printf("a=%f\n", a);