BigDecimal - 用于加舌胶、減、乘锰茉、除計(jì)算的工具類

開發(fā)過程中經(jīng)常會(huì)需要進(jìn)行一些數(shù)據(jù)的運(yùn)算操作,比如加俏脊、減、乘、除,但是在計(jì)算過程中,到底使用哪種數(shù)據(jù)類型進(jìn)行計(jì)算才是最合適的呢赡模?


1田炭、數(shù)據(jù)類型

1.1、 基礎(chǔ)數(shù)據(jù)類型

  • int:只能進(jìn)行整數(shù)的計(jì)算漓柑,應(yīng)用范圍單一教硫。
  • float:單精度浮點(diǎn)型叨吮,可以進(jìn)行小數(shù)類型的計(jì)算,但是容易丟失精度瞬矩。
  • double:雙精度浮點(diǎn)型茶鉴,精確度比float高,消耗的內(nèi)存也比float高景用,但是也容易丟失精度涵叮。
  • String:字符串類型,沒法進(jìn)行運(yùn)算操作丛肢,但是恰恰要用到它和另外一種對象來進(jìn)行數(shù)據(jù)的運(yùn)算操作围肥。
  • BigDecimal :Java在java.math包中提供的API類BigDecimal,用來對超過16位有效位的數(shù)進(jìn)行精確的運(yùn)算蜂怎。

1.2穆刻、BigDecimal 詳細(xì)介紹

以下是關(guān)于BigDecimal 的官方文檔介紹,以及自己的一些總結(jié)杠步。涉及到BigDecimal 以及和它相關(guān)聯(lián)的MathContext氢伟、RoundingMode這兩個(gè)類。

java.math.BigDecimal

  • javase官方文檔的描述:

不可變的幽歼、任意精度的有符號(hào)十進(jìn)制數(shù)朵锣。BigDecimal 由任意精度的整數(shù)非標(biāo)度值 和 32 位的整數(shù)標(biāo)度 (scale) 組成。如果為零或正數(shù)甸私,則標(biāo)度是小數(shù)點(diǎn)后的位數(shù)诚些。如果為負(fù)數(shù),則將該數(shù)的非標(biāo)度值乘以 10 的負(fù) scale 次冪皇型。因此诬烹,BigDecimal 表示的數(shù)值是 (unscaledValue × 10-scale)。
BigDecimal 類提供以下操作:算術(shù)弃鸦、標(biāo)度操作绞吁、舍入、比較唬格、哈希算法和格式轉(zhuǎn)換家破。toString() 方法提供 BigDecimal 的規(guī)范表示形式。
BigDecimal 類使用戶能完全控制舍入行為购岗。如果未指定舍入模式汰聋,并且無法表示準(zhǔn)確結(jié)果,則拋出一個(gè)異常喊积;否則烹困,通過向該操作提供適當(dāng)?shù)?MathContext 對象,可以對已選擇的精度和舍入模式執(zhí)行計(jì)算注服。在任何情況下韭邓,可以為舍入控制提供八種舍入模式。使用此類(例如溶弟,ROUND_HALF_UP)中的整數(shù)字段來表示舍入模式已過時(shí)女淑;應(yīng)改為使用 RoundingMode enum(例如,RoundingMode.HALF_UP)的枚舉值辜御。

java.math.MathContext

  • javase官方文檔描述

該對象是封裝上下文設(shè)置的不可變對象鸭你,它描述數(shù)字運(yùn)算符的某些規(guī)則,例如由 BigDecimal 類實(shí)現(xiàn)的規(guī)則擒权。
基本獨(dú)立設(shè)置為:
1袱巨、precision:某個(gè)操作使用的數(shù)字個(gè)數(shù);結(jié)果舍入到此精度
2碳抄、roundingMode:一個(gè) RoundingMode 對象愉老,該對象指定舍入使用的算法。

java.math.RoundingMode

  • javase官方文檔描述

為可能丟棄精度的數(shù)值操作指定一種舍入行為剖效。每種舍入模式都指示如何計(jì)算返回舍入結(jié)果位數(shù)的最低有效位嫉入。如果返回的位數(shù)比表示精確數(shù)值結(jié)果所需的位數(shù)少,則舍棄的位數(shù)稱為舍棄部分璧尸,而不管這些位數(shù)對數(shù)值的作用如何咒林。換句話說,假設(shè)是一個(gè)數(shù)值爷光,舍棄部分的絕對值可能大于 1垫竞。

  • 這是一種枚舉類型,以下是它的8種舍入方式的總結(jié):
  1. UP

遠(yuǎn)離零方向舍入的舍入模式蛀序。
始終對非零舍棄部分前面的數(shù)字加 1欢瞪。
注意,此舍入模式始終不會(huì)減少計(jì)算值的絕對值哼拔。

  1. DOWN

向零方向舍入的舍入模式引有。
從不對舍棄部分前面的數(shù)字加 1(即截尾)。
注意倦逐,此舍入模式始終不會(huì)增加計(jì)算值的絕對值譬正。

  1. CEILING

向正無限大方向舍入的舍入模式。
如果結(jié)果為正檬姥,則舍入行為類似于 RoundingMode.UP曾我;
如果結(jié)果為負(fù),則舍入行為類似于 RoundingMode.DOWN健民。
注意抒巢,此舍入模式始終不會(huì)減少計(jì)算值。

  1. FLOOR

向負(fù)無限大方向舍入的舍入模式秉犹。
如果結(jié)果為正蛉谜,則舍入行為類似于 RoundingMode.DOWN稚晚;
如果結(jié)果為負(fù),則舍入行為類似于 RoundingMode.UP型诚。
注意客燕,此舍入模式始終不會(huì)增加計(jì)算值。

  1. HALF_UP

向最接近數(shù)字方向舍入的舍入模式狰贯。
如果與兩個(gè)相鄰數(shù)字的距離相等也搓,則向上舍入。
如果被舍棄部分 >= 0.5涵紊,則舍入行為同 RoundingMode.UP傍妒;
否則舍入行為同 RoundingMode.DOWN。
注意摸柄,此舍入模式就是通常學(xué)校里講的四舍五入颤练。

  1. HALF_DOWN

向最接近數(shù)字方向舍入的舍入模式。
如果與兩個(gè)相鄰數(shù)字的距離相等塘幅,則向下舍入昔案。
如果被舍棄部分 > 0.5,則舍入行為同 RoundingMode.UP电媳;
否則舍入行為同 RoundingMode.DOWN踏揣。

  1. HALF_EVEN

向最接近數(shù)字方向舍入的舍入模式。
如果與兩個(gè)相鄰數(shù)字的距離相等匾乓,則向相鄰的偶數(shù)舍入捞稿。
如果舍棄部分左邊的數(shù)字為奇數(shù),則舍入行為同 RoundingMode.HALF_UP拼缝;
如果為偶數(shù)娱局,則舍入行為同 RoundingMode.HALF_DOWN。
注意咧七,在重復(fù)進(jìn)行一系列計(jì)算時(shí)衰齐,此舍入模式可以在統(tǒng)計(jì)上將累加錯(cuò)誤減到最小。此舍入模式也稱為“銀行家舍入法”继阻,主要在美國使用耻涛。此舍入模式類似于 Java 中對 float 和 double 算法使用的舍入策略。

  1. UNNECESSARY

用于斷言請求的操作具有精確結(jié)果的舍入模式瘟檩,因此不需要舍入抹缕。
如果對生成精確結(jié)果的操作指定此舍入模式,則拋出 ArithmeticException墨辛。

  • 來個(gè)表格看一下吧(這是javase官方api的圖表)根據(jù)給定的舍入模式將輸入數(shù)字舍入為一位數(shù)的結(jié)果:
輸入數(shù)字 UP DOWN CEILING FLOOR HALF_UP HALF_DOWN HALF_EVEN UNNECESSARY
5.5 6 5 6 5 6 5 6 拋出 ArithmeticException
2.5 3 2 3 2 3 2 2 拋出 ArithmeticException
1.6 2 1 2 1 2 2 2 拋出 ArithmeticException
1.1 2 1 2 1 1 1 1 拋出 ArithmeticException
1.0 1 1 1 1 1 1 1 1
-1.0 -1 -1 -1 -1 -1 -1 -1 -1
-1.1 -2 -1 -1 -2 -1 -1 -1 拋出 ArithmeticException
-1.6 -2 -1 -1 -2 -2 -2 -2 拋出 ArithmeticException
-2.5 -3 -2 -2 -3 -3 -2 -2 拋出 ArithmeticException
-5.5 -6 -5 -5 -6 -6 -5 -6 拋出 ArithmeticException

注意:以上8中枚舉類型卓研,在使用中需要特別注意,尤其是除法運(yùn)算中的時(shí)候,需要制定枚舉類型奏赘,切記寥闪,切記。

2磨淌、使用環(huán)境

在進(jìn)行開發(fā)工作中橙垢,有時(shí)候會(huì)需要對一些數(shù)據(jù)進(jìn)行加、減伦糯、乘、除的運(yùn)算操作嗽元,這時(shí)候無論用int敛纲、float還是double進(jìn)行計(jì)算,都會(huì)存在精度丟失的風(fēng)險(xiǎn)剂癌,這時(shí)候我們需要借助一個(gè)對象BigDecimal 來幫助我們進(jìn)行計(jì)算淤翔。
BigDecimal 的構(gòu)造方法有許多個(gè),構(gòu)造參數(shù)可以傳int佩谷、float旁壮、double、String谐檀,但是經(jīng)實(shí)際應(yīng)用抡谐,使用構(gòu)造參數(shù)為float或double類型的構(gòu)造參數(shù)進(jìn)行計(jì)算的時(shí)候,轉(zhuǎn)換的BigDecimal 對象都會(huì)導(dǎo)致精度的丟失桐猬。通過實(shí)際驗(yàn)證麦撵,使用構(gòu)造參數(shù)為String的構(gòu)造方法可以避免精度丟失。
注意: 在以后需要進(jìn)行加溃肪、減免胃、乘、出計(jì)算的參數(shù)惫撰,都盡量用String來接收服務(wù)器返回的參數(shù)羔沙。

3、使用方式

以下是封裝的用于進(jìn)行計(jì)算的方法:

加法

  /**
     * 提供精確加法計(jì)算的add方法(例:1+2厨钻,1是被加數(shù)扼雏,2是加數(shù))
     *     
     * @param value1 被加數(shù)
     * @param value2 加數(shù)
     * @return 兩個(gè)參數(shù)的和
     */
    public static String add(String value1, String value2) {
        BigDecimal b1 = new BigDecimal(value1);
        BigDecimal b2 = new BigDecimal(value2);
        return b1.add(b2).toString();
    }

減法

 /**
     * 提供精確減法運(yùn)算的sub方法(例:1-2,1是被減數(shù),2是減數(shù))
     *
     * @param value1 被減數(shù)
     * @param value2 減數(shù)
     * @return 兩個(gè)參數(shù)的差
     */
    public static String sub(String value1, String value2) {
        BigDecimal b1 = new BigDecimal(value1);
        BigDecimal b2 = new BigDecimal(value2);
        return b1.subtract(b2).toString();
    }

乘法

 /**
     * 提供精確乘法運(yùn)算的mul方法(例:1*2,1是被乘數(shù)莉撇,2是乘數(shù))
     *
     * @param value1 被乘數(shù)
     * @param value2 乘數(shù)
     * @return 兩個(gè)參數(shù)的積
     */
    public static String mul(String value1, String value2) {
        BigDecimal b1 = new BigDecimal(value1);
        BigDecimal b2 = new BigDecimal(value2);
        return b1.multiply(b2).toString();
    }

除法

 /**
     * 提供精確的除法運(yùn)算方法div(例:1÷2呢蛤,1是被除數(shù),2是除數(shù))
     *
     * @param value1 被除數(shù)
     * @param value2 除數(shù)
     * @param scale  精確范圍
     * @return 兩個(gè)參數(shù)的商
     * @throws IllegalAccessException
     */
    public static String div(String value1, String value2, int scale) throws IllegalAccessException {
        //如果精確范圍小于0棍郎,拋出異常信息
        if (scale < 0) {
            throw new IllegalAccessException("精確度不能小于0");
        }
        BigDecimal b1 = new BigDecimal(value1);
        BigDecimal b2 = new BigDecimal(value2);
        //指定枚舉類型其障,可以指定RoundingMode的8種枚舉類型之一,對這8種枚舉類型如果有疑問,可以參考上面RoundingMode的總結(jié)和描述堂湖。
        //這里指定的DOWN,對應(yīng)RoundingMode的ROUND_DOWN模式殴俱,會(huì)直接舍去精確度后面的數(shù)值汽抚。
        return b1.divide(b2, scale, RoundingMode.DOWN).toString();
    }

4抓狭、使用總結(jié)

用以上四個(gè)方法就可以應(yīng)付開發(fā)過程中最基礎(chǔ)的加、減造烁、乘否过、除的運(yùn)算了,但是在使用中要注意的情況:被減數(shù)和減數(shù)惭蟋、被除數(shù)和除數(shù)的位置不要顛倒了苗桂,否則就會(huì)和預(yù)期的計(jì)算結(jié)果相差十萬八千里了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末告组,一起剝皮案震驚了整個(gè)濱河市煤伟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌木缝,老刑警劉巖便锨,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異我碟,居然都是意外死亡放案,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門矫俺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卿叽,“玉大人,你說我怎么就攤上這事恳守】加ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵催烘,是天一觀的道長沥阱。 經(jīng)常有香客問我,道長伊群,這世上最難降的妖魔是什么考杉? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮舰始,結(jié)果婚禮上崇棠,老公的妹妹穿的比我還像新娘。我一直安慰自己丸卷,他們只是感情好枕稀,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般萎坷。 火紅的嫁衣襯著肌膚如雪凹联。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天哆档,我揣著相機(jī)與錄音蔽挠,去河邊找鬼。 笑死瓜浸,一個(gè)胖子當(dāng)著我的面吹牛澳淑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播插佛,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼偶惠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了朗涩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對情侶失蹤绑改,失蹤者是張志新(化名)和其女友劉穎谢床,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厘线,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡识腿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了造壮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渡讼。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖耳璧,靈堂內(nèi)的尸體忽然破棺而出成箫,到底是詐尸還是另有隱情,我是刑警寧澤旨枯,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布蹬昌,位于F島的核電站,受9級(jí)特大地震影響攀隔,放射性物質(zhì)發(fā)生泄漏皂贩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一昆汹、第九天 我趴在偏房一處隱蔽的房頂上張望明刷。 院中可真熱鬧,春花似錦满粗、人聲如沸辈末。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽本冲。三九已至准脂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間檬洞,已是汗流浹背狸膏。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留添怔,地道東北人湾戳。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像广料,于是被迫代替她去往敵國和親砾脑。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容