Java BigDecimal解決double精度丟失的問(wèn)題
我們?cè)谌粘i_(kāi)發(fā)中, 有很多時(shí)候會(huì)遇到小數(shù)(double類型)精確計(jì)算, 由于 double 類型在計(jì)算機(jī)中的特殊存儲(chǔ)方式, 某些情況下會(huì)導(dǎo)致精度丟失, 特別是跟錢有關(guān)的計(jì)算, 后臺(tái)校驗(yàn)的時(shí)候, 那得是分毫不差.
場(chǎng)景
商品a價(jià)格是 0.1, 商品b 價(jià)格是 0.2, 用戶買了這兩個(gè)商品, 付款時(shí), 訂單總金額是 0.3, 如果用 double 類型做計(jì)算, 將會(huì)得到結(jié)果 0.30000000000000004, 前端如果拿來(lái)展示總金額, 用戶肯定就蒙圈了, 這顯然不是我們想要的.
那么如何解決呢? Java 給我們提供了專門解決這個(gè)問(wèn)題的類 BigDecimal.
double a = 0.1; double b = 0.2; double c = a + b; System.out.println(c); // 0.30000000000000004
BigDecimal 使用
創(chuàng)建 BigDecimal 對(duì)象
創(chuàng)建對(duì)象一共有3種方式, 兩個(gè)構(gòu)造器, 一個(gè)靜態(tài)方法, 實(shí)際靜態(tài)方法是對(duì)入?yún)?String 的構(gòu)造器的封裝, 即 2, 3 兩種方式本質(zhì)上是一樣的.
// 1 入?yún)⑹?double BigDecimal a = new BigDecimal(0.3); // 2 入?yún)⑹?String BigDecimal b = new BigDecimal("0.3"); // 3 靜態(tài)方法, 入?yún)⑹?double BigDecimal c = BigDecimal.valueOf(0.3);
計(jì)算操作
公用代碼
double a = 0.1; double b = 0.2; BigDecimal a1 = BigDecimal.valueOf(a); BigDecimal b1 = new BigDecimal(Double.toString(b));
1. 加法 add
這就很好的解決了上面場(chǎng)景中出現(xiàn)的問(wèn)題
BigDecimal c1 = a1.add(b1); System.out.println(c1); // 0.3
2. 減法 subtract
BigDecimal c2 = a1.subtract(b1); // 減法 System.out.println(c2); // -0.1
3. 乘法
BigDecimal c3 = a1.multiply(b1); // 乘法 System.out.println(c3); // 0.02
4. 除法
BigDecimal c4 = a1.divide(b1); // 除法 0.1 / 0.3, 無(wú)法除盡, 報(bào)錯(cuò). System.out.println(c4); // 0.5 BigDecimal c5 = a1.divide(c1); // 除法 System.out.println(c5); // 0.1 / 0.3, 無(wú)法除盡, 報(bào)錯(cuò). c5 = a1.divide(c1, 2, RoundingMode.HALF_UP); // 除法 0.1 / 0.3 四舍五入 System.out.println(c5); // 0.5
注意:
BigDecimal 進(jìn)行除法計(jì)算時(shí), 強(qiáng)烈建議使用指定保留小數(shù)倍數(shù)和舍入模式這個(gè)方法, 這樣可以避免除不盡造成的異常.
/** * 參數(shù)1: 除數(shù) * 參數(shù)2: 保留小數(shù)的位數(shù) * 參數(shù)3: 舍入模式 */ public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
5. 保留小數(shù)和舍入模式
設(shè)置保留小數(shù)和舍入模式 setScale 方法
BigDecimal price = new BigDecimal("9.936"); price = price.setScale(2, RoundingMode.HALF_UP); // 2位, 四舍五入 System.out.println(price); // 9.94
6. BigDecimal 轉(zhuǎn)化為 double
double value = c4.doubleValue();
總結(jié)
使用 BigDecimal 計(jì)算時(shí)要注意以下幾點(diǎn):
- 不建議使用入?yún)⑹?double 的構(gòu)造器, 因?yàn)樗匀淮嬖诰葐?wèn)題.
- 強(qiáng)烈建議使用入?yún)⑹?string 的構(gòu)造器, 或者使用靜態(tài)方法 valueOf 創(chuàng)建對(duì)象, 才能保證精度.
- 使用 BigDecimal 做 除法 時(shí), 必須要使用 divide(BigDecimal divisor, int scale, RoundingMode roundingMode), 防止除不盡造成異常.
到此這篇關(guān)于Java BigDecimal解決double精度丟失的問(wèn)題的文章就介紹到這了,更多相關(guān)Java BigDecimal double精度丟失內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring?Cloud?Alibaba負(fù)載均衡實(shí)現(xiàn)方式
這篇文章主要為大家介紹了Spring?Cloud?Alibaba負(fù)載均衡實(shí)現(xiàn)方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Spring?Boot項(xiàng)目集成Knife4j接口文檔的實(shí)例代碼
Knife4j就相當(dāng)于是swagger的升級(jí)版,對(duì)于我來(lái)說(shuō),它比swagger要好用得多<BR>,這篇文章主要介紹了Spring?Boot項(xiàng)目集成Knife4j接口文檔的示例代碼,需要的朋友可以參考下2021-12-12解決nacos升級(jí)spring cloud 2020.0無(wú)法使用bootstrap.yml的問(wèn)題
這篇文章主要介紹了解決nacos升級(jí)spring cloud 2020.0無(wú)法使用bootstrap.yml的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06Spring AOP的幾種實(shí)現(xiàn)方式總結(jié)
本篇文章主要介紹了Spring AOP的幾種實(shí)現(xiàn)方式總結(jié),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02jasypt 集成SpringBoot 數(shù)據(jù)庫(kù)密碼加密操作
這篇文章主要介紹了jasypt 集成SpringBoot 數(shù)據(jù)庫(kù)密碼加密操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11