作者:幻好 來源: 恆生LIGHT雲社群
概述
近日,“拼多多砍價, 砍價永遠差一刀”登上了熱搜,而這個功能在我們周圍的親朋好友中都有過親身體驗。
本次事件具體就去年3月,上海律師劉宇航當時參加了拼多多的“砍價免費拿”活動,領取了一張“超級免單卡”,但邀請多人砍價後,始終差“0.9%”。劉宇航以拼多多在提供網路服務時涉嫌違背誠實信用原則,使用虛假資料隱瞞規則已構成欺詐為由,向法院遞交了起訴材料。在案件審理中,針對劉宇航的起訴以及由此引發的質疑,拼多多表示,因頁面顯示百分比位數有限,所以他們把一個至少小數點後有6位數以上的百分比,省略顯示為0.9%,砍價頁面顯示的0.9%不是0.9%,而是0.9996427%。
本文主要透過這一現實場景,來思考其背後相關的技術實現——Java中精確小數計算。
BigDecimal
應用背景
在Java中 JDK 中提供的 float 和 double 的資料型別,其主要設計目標是為了科學計算和工程計算,由於其執行的二進位制浮點運算,在某些場景下並不能提供精確的結果。比如:
System.out.println(0.1 + 0.2);// 輸出0. 30000000000000004
一個簡單的加法運算,在輸出的結果上並不能保證結果的準確性。其主要原因是在CPU中,表示的浮點數由兩個部分組成:指數和尾數,這樣一般都會導致失去一定的精確度,有些浮點數運算也會產生一定的誤差,浮點數的值實際上是由一個特定的數學公式計算得到的。如:2.4的二進位制表示並非就是精確的1.5。反而最為接近的二進位制表示是 1.59999999999999。
所以在許多需要精確小數計算的商業場景(如支付,商城等),通常需要採用
java.math.BigDecimal
類來進行精確計算。
操作使用
建立
BigDecimal
物件
BigDecimal bigDecimal = new BigDecimal("2022.01054");
通常建議使用
String
型別的構造方法,建立BigDecimal
物件,雖然也可以使用Double
型別的構造方法,但是前面就說過,浮點數本來就不準確,因此轉換的BigDecimal
物件也會不精確。
格式化小數
// 向零方向舍入System.out.println(bigDecimal.setScale(3, BigDecimal.ROUND_DOWN));// 輸出2022.010 // 向遠離0的方向舍入,進位處理new BigDecimal(4.32579).setScale(4, BigDecimal.ROUND_UP);// 輸出2022.011 // 向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向上舍入: >=5new BigDecimal(4.32575).setScale(4, BigDecimal.ROUND_HALF_UP);// 輸出2022.011 // 向(距離)最近的一邊舍入,除非兩邊(的距離)是相等,如果是這樣,向下舍入: >5new BigDecimal(4.32575).setScale(4, BigDecimal.ROUND_HALF_DOWN);// 輸出2022.010
加減乘除運算
// 推薦用字串的形式初始化BigDecimal numFri = new BigDecimal("0.0888"); BigDecimal numSec = new BigDecimal("0.2222"); // 加法BigDecimal resultByAdd = numFri.add(numSec); // 減法BigDecimal resultBySub = numFri.subtract(numSec); // 乘法BigDecimal resultByMul = numFri.multiply(numSec); // 除法BigDecimal resultBydiv = numFri.divide(numSec,20,BigDecimal.ROUND_HALF_UP); // 絕對值BigDecimal resultByAbs = numFri.abs();
BigDecimal
物件在減乘除時,最終都返回的是一個新的BigDecimal
物件,因為BigInteger
與BigDecimal
都是不可變的(immutable)的
,在進行每一步運算時,都會產生一個新的物件
總結
在需要精確計算的重要場景,使用
BigDecimal
,同時推薦使用 String 型別的建構函式建立
BigDecimal
物件。
想向技術大佬們多多取經?開發中遇到的問題何處探討?如何獲取金融科技海量資源?
恆生LIGHT雲社群,由恆生電子搭建的金融科技專業社群平臺,分享實用技術乾貨、資源資料、金融科技行業趨勢,擁抱所有金融開發者。
掃描下方小程式二維碼,加入我們!