<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使用不當(dāng),造成P0事故!

          共 2331字,需瀏覽 5分鐘

           ·

          2022-06-12 23:26

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

          背景

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

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

          事故

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

          問題描述

          收銀臺計(jì)算商品金額報錯,導(dǎo)致訂單無法支付。

          事故級別

          P0

          事故過程

          如下:

          • 13:44,接到報警,訂單支付失敗,支付可用率降至 60%
          • 13:50,迅速回滾上線代碼,恢復(fù)正常
          • 14:20,review 代碼,預(yù)發(fā)布驗(yàn)證發(fā)現(xiàn)問題點(diǎn)
          • 14:58,修改問題代碼上線,線上恢復(fù)

          故障原因

          BigDecimal 在金額計(jì)算中丟失精度。

          原因分析

          首先我們先用一段代碼復(fù)現(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í)行結(jié)果如下:

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

          我們點(diǎn)開構(gòu)造器方法看下源碼:

          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 對應(yīng))中提供了 double 與 long 轉(zhuǎn)換,doubleToRawLongBits 就是將 double 轉(zhuǎn)換為 long,這個方法是原始方法(底層不是 java 實(shí)現(xiàn),是 c++ 實(shí)現(xiàn)的)。

          double 之所以會出問題,是因?yàn)樾?shù)點(diǎn)轉(zhuǎn)二進(jìn)制丟失精度。

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

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

          并沒有提供完全精確的結(jié)果,所以不應(yīng)該被用于精確的結(jié)果的場合。

          當(dāng)浮點(diǎn)數(shù)達(dá)到一定大的數(shù),就會自動使用科學(xué)計(jì)數(shù)法,這樣的表示只是近似真實(shí)數(shù)而不等于真實(shí)數(shù)。

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

          總結(jié)

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



          最近熬夜給大家準(zhǔn)備了非常全的一套Java一線大廠面試題。全面覆蓋BATJ等一線互聯(lián)網(wǎng)公司的面試題及解答,由BAT一線互聯(lián)網(wǎng)公司大牛帶你深度剖析面試題背后的原理,不僅授你以魚,更授你以漁,為你面試掃除一切障礙。



          資源,怎么領(lǐng)取?


          掃二維碼,加我微信,備注:面試題


          一定要備注:面試題,不要急哦,工作忙完后就會通過!





          瀏覽 42
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  亚洲日韩小说图片视频首页 | 中国美女操逼视频 | 久久精彩| 中文字幕在线视频无码 | 四虎影视成人精品一区 |