使用 BigDecimal 进行浮点数运算
BigDecimal 介紹
BigDecimal?可以實現對浮點數的運算,不會造成精度丟失。
通常情況下,大部分需要浮點數精確運算結果的業務場景(比如涉及到錢的場景)都是通過?BigDecimal?來做的。
《阿里巴巴 Java 開發手冊》中提到:浮點數之間的等值判斷,基本數據類型不能用 == 來比較,包裝數據類型不能用 equals 來判斷。
具體原因我們在上面已經詳細介紹了,這里就不多提了。
想要解決浮點數運算精度丟失這個問題,可以直接使用?BigDecimal?來定義浮點數的值,然后再進行浮點數的運算操作即可。
BigDecimal?a?=?new?BigDecimal("1.0"); BigDecimal?b?=?new?BigDecimal("0.9"); BigDecimal?c?=?new?BigDecimal("0.8");BigDecimal?x?=?a.subtract(b); BigDecimal?y?=?b.subtract(c);System.out.println(x.compareTo(y));//?0BigDecimal 常見方法
創建
我們在使用?BigDecimal?時,為了防止精度丟失,推薦使用它的BigDecimal(String val)構造方法或者?BigDecimal.valueOf(double val)?靜態方法來創建對象。
《阿里巴巴 Java 開發手冊》對這部分內容也有提到,如下圖所示。
加減乘除
add?方法用于將兩個?BigDecimal?對象相加,subtract?方法用于將兩個?BigDecimal?對象相減。multiply?方法用于將兩個?BigDecimal?對象相乘,divide?方法用于將兩個?BigDecimal?對象相除。
BigDecimal?a?=?new?BigDecimal("1.0"); BigDecimal?b?=?new?BigDecimal("0.9"); System.out.println(a.add(b));//?1.9 System.out.println(a.subtract(b));//?0.1 System.out.println(a.multiply(b));//?0.90 System.out.println(a.divide(b));//?無法除盡,拋出?ArithmeticException?異常 System.out.println(a.divide(b,?2,?RoundingMode.HALF_UP));//?1.11這里需要注意的是,在我們使用?divide?方法的時候盡量使用 3 個參數版本,并且RoundingMode?不要選擇?UNNECESSARY,否則很可能會遇到?ArithmeticException(無法除盡出現無限循環小數的時候),其中?scale?表示要保留幾位小數,roundingMode?代表保留規則。
public?BigDecimal?divide(BigDecimal?divisor,?int?scale,?RoundingMode?roundingMode)?{return?divide(divisor,?scale,?roundingMode.oldMode); }保留規則非常多,這里列舉幾種:
public?enum?RoundingMode?{//?2.5?->?3?,?1.6?->?2//?-1.6?->?-2?,?-2.5?->?-3UP(BigDecimal.ROUND_UP),//?2.5?->?2?,?1.6?->?1//?-1.6?->?-1?,?-2.5?->?-2DOWN(BigDecimal.ROUND_DOWN),//?2.5?->?3?,?1.6?->?2//?-1.6?->?-1?,?-2.5?->?-2CEILING(BigDecimal.ROUND_CEILING),//?2.5?->?2?,?1.6?->?1//?-1.6?->?-2?,?-2.5?->?-3FLOOR(BigDecimal.ROUND_FLOOR),//?2.5?->?3?,?1.6?->?2//?-1.6?->?-2?,?-2.5?->?-3HALF_UP(BigDecimal.ROUND_HALF_UP),//...... }大小比較
a.compareTo(b)?: 返回 -1 表示?a?小于?b,0 表示?a?等于?b?, 1 表示?a?大于?b。
BigDecimal?a?=?new?BigDecimal("1.0"); BigDecimal?b?=?new?BigDecimal("0.9"); System.out.println(a.compareTo(b));//?1保留幾位小數
通過?setScale方法設置保留幾位小數以及保留規則。保留規則有挺多種,不需要記,IDEA 會提示。
BigDecimal?m?=?new?BigDecimal("1.255433"); BigDecimal?n?=?m.setScale(3,RoundingMode.HALF_DOWN); System.out.println(n);//?1.255BigDecimal 等值比較問題
《阿里巴巴 Java 開發手冊》中提到:
BigDecimal?使用?equals()?方法進行等值比較出現問題的代碼示例:
BigDecimal?a?=?new?BigDecimal("1"); BigDecimal?b?=?new?BigDecimal("1.0"); System.out.println(a.equals(b));//false這是因為?equals()?方法不僅僅會比較值的大小(value)還會比較精度(scale),而?compareTo()?方法比較的時候會忽略精度。
1.0 的 scale 是 1,1 的 scale 是 0,因此?a.equals(b)?的結果是 false。
compareTo()?方法可以比較兩個?BigDecimal?的值,如果相等就返回 0,如果第 1 個數比第 2 個數大則返回 1,反之返回-1。
BigDecimal?a?=?new?BigDecimal("1"); BigDecimal?b?=?new?BigDecimal("1.0"); System.out.println(a.compareTo(b));//0總結
浮點數沒有辦法用二進制精確表示,因此存在精度丟失的風險。
不過,Java 提供了BigDecimal?來操作浮點數。BigDecimal?的實現利用到了?BigInteger?(用來操作大整數), 所不同的是?BigDecimal?加入了小數位的概念。
總結
以上是生活随笔為你收集整理的使用 BigDecimal 进行浮点数运算的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP单例模式使用clone
- 下一篇: 反编译及手机平板apk提取