<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          BigDecimal使用不當,造成P0事故!

          共 1955字,需瀏覽 4分鐘

           ·

          2022-06-09 06:48

          點擊關注公眾號,Java干貨及時送達??

          文章來源:https://c1n.cn/MSqAy


          目錄
          • 背景

          • 事故

          • 分析

          • 總結

          • 工具分享


          背景


          我們在使用金額計算或者展示金額的時候經常會使用 BigDecimal,也是涉及金額時非常推薦的一個類型。


          BigDecimal 自身也提供了很多構造器方法,這些構造器方法使用不當可能會造成不必要的麻煩甚至是金額損失,從而引起事故資損。


          事故


          接下來我們看下收銀臺出的一起事故。


          | 問題描述

          收銀臺計算商品金額報錯,導致訂單無法支付。


          | 事故級別

          P0


          | 事故過程

          如下:

          • 13:44,接到報警,訂單支付失敗,支付可用率降至 60%

          • 13:50,迅速回滾上線代碼,恢復正常

          • 14:20,review 代碼,預發(fā)布驗證發(fā)現(xiàn)問題點

          • 14:58,修改問題代碼上線,線上恢復


          | 故障原因

          BigDecimal 在金額計算中丟失精度。


          原因分析


          首先我們先用一段代碼復現(xiàn)問題根源,如下所示:

          public?static?void?main(String[]?args)?{
          ????BigDecimal?bigDecimal=new?BigDecimal(88);
          ????System.out.println(bigDecimal);
          ????bigDecimal=new?BigDecimal("8.8");
          ????System.out.println(bigDecimal);
          ????bigDecimal=new?BigDecimal(8.8);
          ????System.out.println(bigDecimal);
          }


          執(zhí)行結果如下:

          通過測試發(fā)現(xiàn),當使用 double 或者 float 這些浮點數(shù)據(jù)類型時,會丟失精度,String、int 則不會,這是為什么呢?


          我們點開構造器方法看下源碼:

          public?static?long?doubleToLongBits(double?value)?{
          ????long?result?=?doubleToRawLongBits(value);
          ????//?Check?for?NaN?based?on?values?of?bit?fields,?maximum
          ????//?exponent?and?nonzero?significand.
          ????if?(?((result?&?DoubleConsts.EXP_BIT_MASK)?==
          ??????????DoubleConsts.EXP_BIT_MASK)?&&
          ?????????(result?&?DoubleConsts.SIGNIF_BIT_MASK)?!=?0L)
          ????????result?=?0x7ff8000000000000L;
          ????return?result;
          }


          問題就處在 doubleToRawLongBits 這個方法上,在 jdk 中 double 類(float 與 int 對應)中提供了 double 與 long 轉換,doubleToRawLongBits 就是將 double 轉換為 long,這個方法是原始方法(底層不是 java 實現(xiàn),是 c++ 實現(xiàn)的)。


          double 之所以會出問題,是因為小數(shù)點轉二進制丟失精度。

          BigDecimal 在處理的時候把十進制小數(shù)擴大 N 倍讓它在整數(shù)上進行計算,并保留相應的精度信息。


          float 和 double 類型,主要是為了科學計算和工程計算而設計的,之所以執(zhí)行二進制浮點運算,是為了在廣泛的數(shù)值范圍上提供較為精確的快速近和計算。


          并沒有提供完全精確的結果,所以不應該被用于精確的結果的場合。


          當浮點數(shù)達到一定大的數(shù),就會自動使用科學計數(shù)法,這樣的表示只是近似真實數(shù)而不等于真實數(shù)。


          當十進制小數(shù)位轉換二進制的時候也會出現(xiàn)無限循環(huán)或者超過浮點數(shù)尾數(shù)的長度。


          總結


          所以,在涉及到精度計算的過程中,我們盡量使用 String 類型來進行轉換。

          1.?吊打 ThreadLocal,談談FastThreadLocal為啥能這么快?

          2.?jQuery已經是時代的眼淚了嗎?

          3.?Istio 可以代替 SpringCloud 嗎?

          4.?SpringBoot 實現(xiàn) Office 各種格式在線預覽(詳細教程,包教包會)

          最近面試BAT,整理一份面試資料Java面試BATJ通關手冊,覆蓋了Java核心技術、JVM、Java并發(fā)、SSM、微服務、數(shù)據(jù)庫、數(shù)據(jù)結構等等。

          獲取方式:點“在看”,關注公眾號并回復?Java?領取,更多內容陸續(xù)奉上。

          PS:因公眾號平臺更改了推送規(guī)則,如果不想錯過內容,記得讀完點一下在看,加個星標,這樣每次新文章推送才會第一時間出現(xiàn)在你的訂閱列表里。

          “在看”支持小哈呀,謝謝啦??

          瀏覽 51
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一级黄色日皮 | 操操操操操操操操逼 | 欧美日逼视频网址 | 日韩精品久久久久 | 韩国三级91|