2013-03-25 34 views
22

所以當我用Doubles添加或減去Java時,它給了我奇怪的結果。這裏有一些:增加和減少雙打給出奇怪的結果

如果我加0.0 + 5.1,它給我5.1。這是正確的。

如果我加5.1 + 0.1,它給我5.199999999999(重複9的數量可能會關閉)。這是錯誤的。

如果我減去4.8 - 0.4,它給我4.39999999999995(同樣,重複9可能會關閉)。這是錯誤的。

起初我以爲這只是添加十進制值的雙打問題,但我錯了。以下工作得很好:

5.1 + 0.2 = 5.3 
5.1 - 0.3 = 4.8 

現在,添加的第一個號碼是保存爲一個變量雙,雖然第二個變量抓住從JTextField文本。例如:

//doubleNum = 5.1 RIGHT HERE 
//The textfield has only a "0.1" in it. 
doubleNum += Double.parseDouble(textField.getText()); 
//doubleNum = 5.199999999999999 
+0

順便說一句,更喜歡使用BigDecimal(http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html) – user2147970 2013-03-25 21:59:30

+0

其實,5.19999999 ...(無限多重複9 )在數學上與5.2完全相同,如果你不相信,試着找出兩者之間的區別。它是0,因此它們是相同的。 – Ingo 2013-03-25 22:06:27

+0

@在技術上,是的,但我想有一個精確的答案:) – 2013-03-25 22:12:09

回答

24

在Java中,double的值爲IEEE floating point numbers。除非它們是2的冪(或者2的冪的和,例如1/8 + 1/4 = 3/8),否則即使它們具有高精度,也不能精確地表示它們。一些浮點運算會複合這些浮點數中存在的舍入誤差。在上面描述的情況下,浮點錯誤已經變得足夠重要,以顯示在輸出中。

不要緊,什麼號碼的來源,無論是分析從JTextField字符串或指定double文字 - 問題是在浮點表示繼承。

解決方法:

  • 如果你知道你只有這麼多的小數點,然後使用整數算術 ,然後轉換爲十進制:

    (double) (51 + 1)/10 
    (double) (48 - 4)/10 
    
  • 使用BigDecimal

  • 如果您必須使用double,則可以減少浮點錯誤 與Kahan Summation Algorithm

+0

您是否認爲如果我使用「浮動」而不是它會給出更準確的值? – 2013-03-25 21:58:54

+0

'float'通常只有'double'的一半精度。如果你需要精確度,這不是一個好主意。 – rgettman 2013-03-25 22:00:41

+0

@ngo:好的;我已經更新了我的答案。 – rgettman 2013-03-25 22:04:57

2

在Java中,雙打使用IEEE 754浮點運算(見this維基百科文章),它本質上是不準確的。使用BigDecimal獲得完美的小數精度。要打印圓形,只接受「相當不錯」的精度,請使用printf("%.3f", x)