2012-07-03 73 views
0

據我所知,著名IEEE 754:Java腳本對C

(0.1 + 0.2) !== 0.3 

疑難雜症實際上不是JavaScript的錯。這就是IEEE 754的工作方式。 Python中也有類似的輸出,它也遵循IEEE 754規則。

那麼這個特定的例子如何在C中預期的工作,有時。如果我做一個直接的比較

printf("%d\n", (0.1+0.2) == 0.3); 

我得到的(未?)預期產出0,但如果我把值變量或者打印出來,我得到適當的四捨五入的答案。

C Runnable Example

是C實現的IEEE 754的做一些額外的東西?或者是我缺少的其他東西。

更新

我張貼的代碼示例是由於一個錯字打破。嘗試這一個 Fixed C Runnable Example

但原來的問題仍然存在。

double d1, d2, d3; 
d1 = 0.1; d2 = 0.2; d3 = d1 + d2; 
printf ("%d\n", ((((double)0.1)+((double)0.2)) == ((double)d3))); 
printf ("%.17f\n", d1+d2); 
printf ("%d\n", ((d1+d2) == d3)); 

輸出是

1 
0.30000000000000004 
1 

的改寫現在的問題是:

  1. 爲何(以及何時,以及如何)是C編譯器採取自由地說,

    0.3 == 0.30000000000000004

  2. 考慮到所有的事實,是不是真的C實現被破壞,而不是Javascript的?

+3

您的代碼示例中,你從來沒有真正打印任何不是整數的數字。 – Alnitak

+0

你的問題與JavaScript沒有任何關係。它必須處理C和處理雙打,有時你會得到一個結果,而其他時候你會得到不同的結果。 (我的猜測是,有時,預處理器做數學,還等什麼的*編譯*看到的是'的printf(「%d \ n」,0.3 == 0.3);',但它只是一個猜測) –

+1

@Manav:即使你也提供了一個鏈接,總是在問題本身中包含相關的代碼(和輸出)**。您目前在問題中的代碼與您鏈接的代碼有*不同,鏈接可能會失效。更多:http://meta.stackexchange.com/questions/118392/add-stack-overfow-faq-entry-or-similar-for-putting-code-in-the-question –

回答

4

爲何(以及何時,以及如何)是C編譯器採取自由地說,

0.3 == 0.30000000000000004 

考慮到所有的事實,是不是真正的C實現被打破,而比Javascript的'?

不是。

給出的輸出是從這個代碼:

printf ("%d\n", ((((double)0.1)+((double)0.2)) == ((double)d3))); 

但你寫道:

d1 = 0.1; d2 = 0.2; d3 = d1 + d2; 

所以d30.3,這是0.30000000000000004

+0

所以沒有人破碎。這只是一個糟糕的名字,而Javascript的名字很糟糕:) – Manav

+1

@Manav甚至沒有這個意思 - 人們只是不瞭解IEEE 754. – Alnitak

+0

如果你改成'd3 = 0.3',那麼你的'printf(「%d \ n「,d1 + d2 == d3);'再次變成假。 –

0

您的示例代碼使用1,2和(1 + 2),它們都可以用雙精度浮點完全表示。另一方面,0.1不能完全表示浮點數,因此你可以近似得到這個數。當大約增加0.1到大約0.2時,你將得到大約0.3,但是這是否與編譯器在表示0.3時可以選擇的近似值完全相同。

該表示法使用二進制。這意味着它使用1/2,1/4,1/8,1/16,1/32(依此類推以達到許多精度....)。這意味着0.5,0.25等都可以精確地表示出來。不是二進制分數的精確和的數字可以非常接近地近似。

解決方案:不要將浮點數相互比較。將他們的差異與您不關心的一些小數字進行比較。

#define EPSILON 0.000001 
printf("%d", fabs((0.1+0.2) - 0.3) < EPSILON); 

我不知道爲什麼C代碼的工作原理和蟒蛇/ JavaScript沒有。這是魔法。但希望無論如何這回答你的問題。

+1

我想知道這個'魔術「,你在你的答案的最後一行中提到。 – Manav

+0

我在更新之前回答了一個新的代碼示例。前一個被打破,根本沒有比較小數。所以我不知道他爲什麼認爲他的C代碼工作,而JavaScript沒有(尤其是沒有JavaScript代碼示例)。所以我解釋了浮點數是如何表示的,以及爲什麼算術中沒有精確的答案,以及爲什麼一個實現可能工作而另一個實現可能工作。因此,比較浮動是否平等會起作用是「魔術」。即不要這樣做。 – dave

1
`printf("%d\n", (0.1+0.2) == 0.3);` 

這些是DOUBLE不FLOATs。

務必:

printf("%d\n", (0.1+0.2) == 0.3); 
printf("%d\n", (0.1f+0.2f) == 0.3f); 

,瞧!

http://codepad.org/VF9svjxY

Output: 
0 
1 

退房這個問題。這與其他問題有關,但使用GCC的ppl與使用MSVC的ppl得到不同的結果。 printing the integral part of a floating point number

+1

MSVC在64位模式下使用SSE FPU,在32位模式下使用x87 FPU。後者以80位精度存儲所有中間結果。有可能通過中間商店和重新加載來解決這個問題。 –