Java踩坑記系列之BigDecimal

java.math包中提供了對大數(shù)字的操作類挖诸,用于進(jìn)行高精確計算兑牡,如BigIntegerBigDecimal類税灌。而平常我們開發(fā)中使用最多的floatdouble只能適用于一般的科學(xué)和工程計算均函,如果要在比較精確的計算方面如貨幣,那么使用float和double會相應(yīng)的丟失精度菱涤,因此用于精密計算大數(shù)字的類BigDecimal就必不可少了苞也。所以BigDecimal適合商業(yè)計算場景,用來對超過16位有效位的數(shù)進(jìn)行精確的運算粘秆。但是BigDecimal的使用并不像float和double那樣如迟,使用不當(dāng)造成的后果更嚴(yán)重,下面就來看下我們項目中踩過BigDecimal的坑:

一. BigDecimal的初始化精度丟失問題

先來看下面代碼的運行結(jié)果:

BigDecimal bd1 = new BigDecimal(0.1);
System.out.println("bd1="+bd1);
BigDecimal bd2 = new BigDecimal("0.1");
System.out.println("bd2="+bd2);
BigDecimal bd3 = BigDecimal.valueOf(0.1);
System.out.println("bd3="+bd3);

輸出結(jié)果:

bd1=0.1000000000000000055511151231257827021181583404541015625
bd2=0.1
bd3=0.1

如果是float或double類型轉(zhuǎn)Bigdecimal,不要使用new BigDecimal()轉(zhuǎn), 使用valueOf()方法 或 new BigDecimal("")轉(zhuǎn)成string殷勘,否則有可能出現(xiàn)精度問題此再。

《Effective Java》這本書里說過:

如果需要精確的答案,請避免使用float和double

因為float和double執(zhí)行的是二進(jìn)制浮點運算玲销,二進(jìn)制有些情況下不能準(zhǔn)確的表示一個小數(shù)输拇,就像十進(jìn)制不能準(zhǔn)確的表示1/3(1/3=0.3333...)也就是說二進(jìn)制表示小數(shù)的時候只能夠表示能夠用1/(2^n)的和的任意組合,例如:

0.5能夠表示贤斜,因為它可以表示成為1/2

0.75也能夠表示策吠,因為它可以表示成為1/2+1/(2^2)

0.875也能夠表示,因為它可以表示成為1/2+1/(22)+1/(23)

但是0.1不能夠精確表示瘩绒,因為它不能夠表示成為1/(2^n)的和的形式

System.out.println(0.5*3);
System.out.println(0.1*3);

大家可以本地執(zhí)行下這兩行代碼猴抹,看下輸出結(jié)果就知道為什么二進(jìn)制不能表示0.1卻可以表示0.5了。所以其實不是BigDecimal的問題锁荔,BigDecimal就是為了滿足精確運算存在的蟀给,問題出在0.1它本身就一個不準(zhǔn)確的值,這其實跟BigDecimal無關(guān)阳堕,但在使用的時候需要注意用法跋理。

二. BigDecimal在進(jìn)行除法運算時需設(shè)置精度,否則對于除不盡的情況會拋出異常

繼續(xù)看下面的代碼執(zhí)行結(jié)果:

BigDecimal bd4 = new BigDecimal("10");
BigDecimal bd5 = new BigDecimal("3");
System.out.println(bd4.divide(bd5));

輸出結(jié)果:

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1690)
at BigDecimalTest.main(BigDecimalTest.java:38)

應(yīng)該向下面這樣設(shè)置小數(shù)點后的位數(shù),以及超出后是四舍五入和向上/向下取整或者直接舍棄:

System.out.println(bd4.divide(bd5,2,BigDecimal.ROUND_DOWN));

第二個參數(shù)表示小數(shù)位數(shù),第三個參數(shù)表示超出的位數(shù)直接舍棄(當(dāng)然也可以設(shè)置四舍五入嘱丢,向上取整等)

三. 不要使用BigDecimal的equals方法比較大小, 否則可能會因為精度問題導(dǎo)致比較結(jié)果和預(yù)期的不一致

BigDecimal bd1 = new BigDecimal("0");
BigDecimal bd2 = new BigDecimal("0.0");
System.out.println(bd1.equals(bd2));
System.out.println(bd1.compareTo(bd2) == 0)

輸出結(jié)果:

equals:false
compareTo:true

如果你無法確定你的BigDecimal值有小數(shù)情況薪介,最好用compareTo祠饺!

文章來源:http://javakk.com/563.html
也歡迎大家關(guān)注我的公眾號【Java老K】獲取更多干貨

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末越驻,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子道偷,更是在濱河造成了極大的恐慌缀旁,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件勺鸦,死亡現(xiàn)場離奇詭異并巍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)换途,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進(jìn)店門懊渡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人军拟,你說我怎么就攤上這事剃执。” “怎么了懈息?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵肾档,是天一觀的道長。 經(jīng)常有香客問我,道長怒见,這世上最難降的妖魔是什么俗慈? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮遣耍,結(jié)果婚禮上闺阱,老公的妹妹穿的比我還像新娘。我一直安慰自己配阵,他們只是感情好馏颂,可當(dāng)我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著棋傍,像睡著了一般救拉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瘫拣,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天亿絮,我揣著相機(jī)與錄音,去河邊找鬼麸拄。 笑死派昧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的拢切。 我是一名探鬼主播蒂萎,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼淮椰!你這毒婦竟也來了五慈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤主穗,失蹤者是張志新(化名)和其女友劉穎泻拦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體忽媒,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡争拐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晦雨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片架曹。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖闹瞧,靈堂內(nèi)的尸體忽然破棺而出绑雄,到底是詐尸還是另有隱情,我是刑警寧澤夹抗,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布绳慎,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏杏愤。R本人自食惡果不足惜靡砌,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望珊楼。 院中可真熱鬧通殃,春花似錦、人聲如沸厕宗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽已慢。三九已至曲聂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間佑惠,已是汗流浹背朋腋。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留膜楷,地道東北人旭咽。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像赌厅,于是被迫代替她去往敵國和親穷绵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,691評論 2 361