2008-11-29 163 views
9

在我的節目,我有一個數組25個值0.04 當我嘗試在一個循環來總結這些價值觀,我得到以下結果:奇怪的浮點行爲

0.0 + 0.04 = 0.04 
0.04 + 0.04 = 0.08 
0.08 + 0.04 = 0.12 
0.12 + 0.04 = 0.16 
0.16 + 0.04 = 0.2 
0.2 + 0.04 = 0.24000000000000002 
0.24000000000000002 + 0.04 = 0.28 
0.28 + 0.04 = 0.32 
0.32 + 0.04 = 0.36 
0.36 + 0.04 = 0.39999999999999997 
0.39999999999999997 + 0.04 = 0.43999999999999995 
0.43999999999999995 + 0.04 = 0.4799999999999999 
0.4799999999999999 + 0.04 = 0.5199999999999999 
0.5199999999999999 + 0.04 = 0.5599999999999999 
0.5599999999999999 + 0.04 = 0.6 
0.6 + 0.04 = 0.64 
0.64 + 0.04 = 0.68 
0.68 + 0.04 = 0.7200000000000001 
0.7200000000000001 + 0.04 = 0.7600000000000001 
0.7600000000000001 + 0.04 = 0.8000000000000002 
0.8000000000000002 + 0.04 = 0.8400000000000002 
0.8400000000000002 + 0.04 = 0.8800000000000002 
0.8800000000000002 + 0.04 = 0.9200000000000003 
0.9200000000000003 + 0.04 = 0.9600000000000003 

爲什麼地球上會發生嗎?!

+0

有點相關的問題:http://stackoverflow.com/questions/327020/why-are-floating-point-values-so-prolific – CesarB 2008-11-29 14:36:51

回答

23

編程語言中最常見的浮點值存儲 - IEEE singles and doubles - 對大多數小數沒有精確表示。

原因是它們以二進制浮點格式存儲值,而不是十進制浮點格式。唯一可以精確表示的小數值是兩個負冪的和。號碼,如:

  • 0.5(2^-1)
  • 0.125(2^-3)
  • 0.625(2^-1 + 2^-3)

等等

你所看到的是這樣一個事實,即像0.96這樣的數字的表示不能完全表示,因爲它們不能表示爲兩個負冪的和。因此,當作爲小數部分以完全精確度打印出來時,它們不會與原始值匹配。

+0

「而不是小數」有點錯誤的想法。如果它使用了十進制,它將被限制爲小數值,這是10的負冪的和,所以這不會真正解決太多。有人讀到你的答案可能會得出這樣的想法:「如果只有他們使用base10」 – jalf 2008-11-29 14:59:01

+0

@jalf,這個問題就會消失,但至少有一個十進制浮點表示會讓更少的人用於簡單的口袋會計。增加一堆20個鎳幣而不是完全降價對許多人來說是令人驚訝的。一個十進制符號會讓這種情況變得正確,並且用有趣的問題來交換那些應該從小學課程算術課程中熟悉的數字。 – RBerteig 2009-06-12 23:27:44

5

其他的答案中提到爲什麼,但不知道如何避免它。

有幾種解決方案:

  • 縮放:如果您所有的數字是0.01的倍數(例如),乘以100的一切,使用整數運算(這是精確的)。
  • 數字類型:如果您的語言具有數字類型(如SQL中的numeric類型),則可以使用它。
  • 任意精度的理由:使用像GMP這樣的數據庫,它允許您將這些數字表示爲兩個整數的比率。
  • 十進制浮點數:如果你有一個像IEEE-754r那樣的十進制浮點數,你可以使用它。
1

您可能希望查看java BigDecimal類作爲浮動和雙打的替代方法。