<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    BigDecimal使用不當(dāng),造成P0事故!

    共 1955字,需瀏覽 4分鐘

     ·

    2022-06-09 06:48

    點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)??

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


    目錄
    • 背景

    • 事故

    • 分析

    • 總結(jié)

    • 工具分享


    背景


    我們?cè)谑褂媒痤~計(jì)算或者展示金額的時(shí)候經(jīng)常會(huì)使用 BigDecimal,也是涉及金額時(shí)非常推薦的一個(gè)類型。


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


    事故


    接下來我們看下收銀臺(tái)出的一起事故。


    | 問題描述

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


    | 事故級(jí)別

    P0


    | 事故過程

    如下:

    • 13:44,接到報(bào)警,訂單支付失敗,支付可用率降至 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é)果如下:

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


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


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

    BigDecimal 在處理的時(shí)候把十進(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é)果的場(chǎng)合。


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


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


    總結(jié)


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

    1.?吊打 ThreadLocal,談?wù)凢astThreadLocal為啥能這么快?

    2.?jQuery已經(jīng)是時(shí)代的眼淚了嗎?

    3.?Istio 可以代替 SpringCloud 嗎?

    4.?SpringBoot 實(shí)現(xiàn) Office 各種格式在線預(yù)覽(詳細(xì)教程,包教包會(huì))

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

    獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù)?Java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

    PS:因公眾號(hào)平臺(tái)更改了推送規(guī)則,如果不想錯(cuò)過內(nèi)容,記得讀完點(diǎn)一下在看,加個(gè)星標(biāo),這樣每次新文章推送才會(huì)第一時(shí)間出現(xiàn)在你的訂閱列表里。

    點(diǎn)“在看”支持小哈呀,謝謝啦??

    瀏覽 51
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    大香蕉日韩| 伊人激情综合 | 日韩视频在线观看 | 久久久中文字幕三级电影网 | 黄色电影高清无码在线观看 |