Java中Double和Float精度丟失問題及解決方法


文章轉至:https://www.cnblogs.com/cblogs/p/double-precision.html

在討論兩位double數0.2和0.3相加時,毫無疑問他們相加的結果是0.5。但是問題總是如此嗎?

下面我們讓下面兩個doubles數相加,然后看看輸出結果:

@Test
public void testBig(){
    System.out.println(0.11+2001299.32);
}

 

控制台輸出2001299.4300000002

我們吃驚的發現,結果並不是我們預想的那樣,這是為什么呢?又如何解決呢?

現貼出BigDecimal的一個構造函數的文檔供大家參考

BigDecimal

public BigDecimal(double val)

將 double 轉換為 BigDecimal,后者是 double 的二進制浮點值准確的十進制表示形式。返回的 BigDecimal 的標度是使 (10scale × val) 為整數的最小值。

注:

  1. 此構造方法的結果有一定的不可預知性。有人可能認為在 Java 中寫入 new BigDecimal(0.1) 所創建的 BigDecimal 正好等於 0.1(非標度值 1,其標度為 1),但是它實際上等於 0.1000000000000000055511151231257827021181583404541015625。這是因為 0.1 無法准確地表示為 double(或者說對於該情況,不能表示為任何有限長度的二進制小數)。這樣,傳入 到構造方法的值不會正好等於 0.1(雖然表面上等於該值)。
  2. 另一方面,String 構造方法是完全可預知的:寫入 new BigDecimal("0.1") 將創建一個 BigDecimal,它正好 等於預期的 0.1。因此,比較而言,通常建議優先使用 String 構造方法
  3. 當 double 必須用作 BigDecimal 的源時,請注意,此構造方法提供了一個准確轉換;它不提供與以下操作相同的結果:先使用 Double.toString(double) 方法,然后使用 BigDecimal(String) 構造方法,將 double 轉換為 String。要獲取該結果,請使用 static valueOf(double) 方法。

解決方法:

相信從上面的文檔大家也已經找出了解決方法,

在需要精確的表示兩位小數時我們需要把他們轉換為BigDecimal對象,然后再進行運算。

另外需要注意

使用BigDecimal(double val)構造函數時仍會存在精度丟失問題,建議使用BigDecimal(String val)

這就需要先把double轉換為字符串然后在作為BigDecimal(String val)構造函數的參數。轉換為BigDecimal對象

之后再進行加減乘除操作,這樣精度就不會出現問題了。這也是為什么有關金錢數據存儲都使用BigDecimal。

@Test
public void testBig(){
    System.out.println(0.11+2001299.32);//非精確的輸出
    BigDecimal bigDecimal1 = new BigDecimal(Double.toString(0.11));
    BigDecimal bigDecimal2 = new BigDecimal(Double.toString(2001299.32));
    System.out.println(bigDecimal1.add(bigDecimal2));//精確的輸出
}

  

控制台輸出:

2001299.4300000002
2001299.43


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM