2012-03-28 88 views
10

我的同事做了這個實驗:雙減法精度問題

public class DoubleDemo { 

     public static void main(String[] args) { 
      double a = 1.435; 
      double b = 1.43; 
      double c = a - b; 
      System.out.println(c); 
     } 
} 

對於這個一年級的操作我預計這樣的輸出:

0.005 

但沒想到的產量爲:

0.0050000000000001155 

爲什麼double在這麼簡單的操作中失敗?如果double不是這項工作的數據類型,我應該使用什麼?

+0

感謝您分享您的實驗。 +1 – kasavbere 2012-03-28 15:46:13

+0

我敢肯定,這是[保留精度雙打在Java]重複 – 2012-03-28 15:47:17

+0

可能重複(http://stackoverflow.com/questions/322749/retain-precision-with-doubles-in-java) – 2012-03-28 15:49:23

回答

17

double在內部存儲爲一個分數在二進制 - 像1/4 + 1/8 + 1/16 + ...

0.005 - 或值1.435 - 不能被存儲爲確切小數二進制,所以double不能存儲的確切值爲0.005,減法值不完全確切。

如果您關心精確的十進制算術,請使用BigDecimal

您還可能會發現this article有用的閱讀。

+0

+ 1使用BigDecimal或舍入結果。 – 2012-03-28 17:59:12

2

double和float是不完全是實數

在任何範圍內都有無數的實數,但只有有限的位數來表示它們!由於這個原因,雙精度和浮點數預計會有舍入誤差。

您得到的數字是可能的最接近的數字,可以用浮點表示中的double來表示。

有關更多詳細信息,您可能需要閱讀this article [警告:可能是高級別]。

您可能希望使用BigDecimal來得到完整的十進制數[但當您嘗試獲取1/3時,您將再次遇到舍入錯誤。

1

doublefloat由於發生在「引擎蓋下」的四捨五入,算術運算永遠不會是完全正確的。

基本上雙打和浮動可以有無限的小數,但在內存中它們必須由一些實數位表示。所以,當你做這個十進制算術時,會發生一個舍入過程,如果你考慮所有的小數,通常會被忽略。

正如前面所說,如果你需要完全精確的值,則使用BigDecimal其不同存儲其值。 Here's the API

+0

說他們「永不」完全正確是不準確的。說分母不是2的冪的分數以外的其他分數時,它們絕不會是完全正確的。 – supercat 2015-02-15 17:36:53

-1
//just try to make a quick example to make b to have the same precision as a has, by using BigDecimal 

private double getDesiredPrecision(Double a, Double b){ 
    String[] splitter = a.toString().split("\\."); 
    splitter[0].length(); // Before Decimal Count 
    int numDecimals = splitter[1].length(); //After Decimal Count 

    BigDecimal bBigDecimal = new BigDecimal(b); 
    bBigDecimal = bBigDecimal.setScale(numDecimals,BigDecimal.ROUND_HALF_EVEN); 

    return bBigDecimal.doubleValue(); 
} 
+0

這並沒有回答這個問題。 – 2014-08-15 14:08:27

+0

好吧,你是對的。試着在BigDecimal上做一些小例子。已經有人回答這個問題。不需要重複。 – madmaximshen 2014-08-15 15:21:43

+0

在SO上,答案是提供一個完整的,自包含的答案。如果您覺得在其他答案中缺少某些內容,請在您擁有足夠的信譽後留下評論。如果你認爲你可以寫一個更好的*完整*答案,那麼做。不要發佈這樣的「半答案」。 – 2014-08-15 15:27:26