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