(商業(yè)中為何不用Float Double)Java BigDecimal詳解

1.引言

float和double類型的主要設(shè)計目標是為了科學計算和工程計算屎蜓。他們執(zhí)行二進制浮點運算粉洼,這是為了在廣域數(shù)值范圍上提供較為精確的快速近似計算而精心設(shè)計的刀崖。然而颖榜,它們沒有提供完全精確的結(jié)果棚饵,所以不應(yīng)該被用于要求精確結(jié)果的場合煤裙。但是,商業(yè)計算往往要求結(jié)果精確蟹地,這時候BigDecimal就派上大用場啦积暖。

先看下面代碼:

public static void main(String[] args)
    {
        System.out.println(0.2 + 0.1);
        System.out.println(0.3 - 0.1);
        System.out.println(0.2 * 0.1);
        System.out.println(0.3 / 0.1);
    }

運行結(jié)果如下:


image.png

你認為你看錯了,但結(jié)果卻是是這樣的怪与。問題在哪里呢?原因在于我們的計算機是二進制的缅疟。浮點數(shù)沒有辦法是用二進制進行精確表示分别。我們的CPU表示浮點數(shù)由兩個部分組成:指數(shù)和尾數(shù),這樣的表示方法一般都會失去一定的精確度存淫,有些浮點數(shù)運算也會產(chǎn)生一定的誤差耘斩。如:2.4的二進制表示并非就是精確的2.4。反而最為接近的二進制表示是 2.3999999999999999桅咆。浮點數(shù)的值實際上是由一個特定的數(shù)學公式計算得到的括授。

其實java的float只能用來進行科學計算或工程計算,在大多數(shù)的商業(yè)計算中岩饼,一般采用java.math.BigDecimal類來進行精確計算荚虚。

2.BigDecimal構(gòu)造方法

1.public BigDecimal(double val) 將double表示形式轉(zhuǎn)換為BigDecimal 不建議使用這個構(gòu)造函數(shù)
2.public BigDecimal(int val)  將int表示形式轉(zhuǎn)換成BigDecimal
3.public BigDecimal(String val)  將String表示形式轉(zhuǎn)換成BigDecimal

為什么不建議采用第一種構(gòu)造方法呢?來看例子

    {
        BigDecimal bigDecimal = new BigDecimal(2);
        BigDecimal bDouble = new BigDecimal(2.3);
        BigDecimal bString = new BigDecimal("2.3");
        System.out.println("bigDecimal=" + bigDecimal);
        System.out.println("bDouble=" + bDouble);
        System.out.println("bString=" + bString);
    }

運行結(jié)果如下:


image.png

為什么會出現(xiàn)這種情況呢籍茧?

JDK的描述:

1版述、參數(shù)類型為double的構(gòu)造方法的結(jié)果有一定的不可預(yù)知性。有人可能認為在Java中寫入newBigDecimal(0.1)所創(chuàng)建的BigDecimal正好等于 0.1(非標度值 1寞冯,其標度為 1)渴析,但是它實際上等于0.1000000000000000055511151231257827021181583404541015625。這是因為0.1無法準確地表示為 double(或者說對于該情況吮龄,不能表示為任何有限長度的二進制小數(shù))俭茧。這樣,傳入到構(gòu)造方法的值不會正好等于 0.1(雖然表面上等于該值)漓帚。
2母债、 另一方面,String 構(gòu)造方法是完全可預(yù)知的:寫入 newBigDecimal("0.1") 將創(chuàng)建一個 BigDecimal胰默,它正好等于預(yù)期的 0.1场斑。因此,比較而言牵署,通常建議優(yōu)先使用String構(gòu)造方法漏隐。

當double必須用作BigDecimal的源時,請使用Double.toString(double)轉(zhuǎn)成String奴迅,然后使用String構(gòu)造方法青责,或使用BigDecimal的靜態(tài)方法valueOf挺据,如下

public static void main(String[] args)
    {
        BigDecimal bDouble1 = BigDecimal.valueOf(2.3);
        BigDecimal bDouble2 = new BigDecimal(Double.toString(2.3));

        System.out.println("bDouble1=" + bDouble1);
        System.out.println("bDouble2=" + bDouble2);
        
    }

結(jié)果:
image.png

3.BigDecimal加減乘除運算

對于常用的加,減脖隶,乘扁耐,除,BigDecimal類提供了相應(yīng)的成員方法产阱。

public BigDecimal subtract(BigDecimal value);                   //減法 
public BigDecimal multiply(BigDecimal value);                   //乘法
public BigDecimal divide(BigDecimal value);                     //除法

大概的用法如下

public static void main(String[] args)
    {
        BigDecimal a = new BigDecimal("4.5");
        BigDecimal b = new BigDecimal("1.5");

        System.out.println("a + b =" + a.add(b));
        System.out.println("a - b =" + a.subtract(b));
        System.out.println("a * b =" + a.multiply(b));
        System.out.println("a / b =" + a.divide(b));
    }

運行結(jié)果
image.png

這里有一點需要注意的是除法運算divide.
BigDecimal除法可能出現(xiàn)不能整除的情況婉称,比如 4.5/1.3,這時會報錯java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

其實divide方法有可以傳三個參數(shù)

public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) 

第一參數(shù)表示除數(shù)构蹬, 二個參數(shù)表示小數(shù)點后保留位數(shù)王暗,第三個參數(shù)表示舍入模式。

只有在作除法運算或四舍五入時才用到舍入模式庄敛,有下面這幾種:

ROUND_UP :向遠離零的方向舍入俗壹。舍棄非零部分,并將非零舍棄部分相鄰的一位數(shù)字加一藻烤。

ROUND_DOWN :向接近零的方向舍入绷雏。舍棄非零部分,同時不會非零舍棄部分相鄰的一位數(shù)字加一怖亭,采取截取行為涎显。

ROUND_CEILING :向正無窮的方向舍入。如果為正數(shù)依许,舍入結(jié)果同ROUND_UP一致棺禾;如果為負數(shù),舍入結(jié)果同ROUND_DOWN一致峭跳。注意:此模式不會減少數(shù)值大小膘婶。

ROUND_FLOOR :向負無窮的方向舍入。如果為正數(shù)蛀醉,舍入結(jié)果同

ROUND_DOWN一致悬襟;如果為負數(shù),舍入結(jié)果同ROUND_UP一致拯刁。注意:此模式不會增加數(shù)值大小脊岳。

ROUND_HALF_UP :向“最接近”的數(shù)字舍入,如果與兩個相鄰數(shù)字的距離相等垛玻,則為向上舍入的舍入模式割捅。如果舍棄部分>= 0.5,則舍入行為與ROUND_UP相同帚桩;否則舍入行為與ROUND_DOWN相同亿驾。這種模式也就是我們常說的我們的“四舍五入”。

ROUND_HALF_DOWN :向“最接近”的數(shù)字舍入账嚎,如果與兩個相鄰數(shù)字的距離相等莫瞬,則為向下舍入的舍入模式儡蔓。如果舍棄部分> 0.5,則舍入行為與ROUND_UP相同疼邀;否則舍入行為與ROUND_DOWN相同喂江。這種模式也就是我們常說的我們的“五舍六入”。

ROUND_HALF_EVEN :向“最接近”的數(shù)字舍入旁振,如果與兩個相鄰數(shù)字的距離相等获询,則相鄰的偶數(shù)舍入。如果舍棄部分左邊的數(shù)字奇數(shù)拐袜,則舍入行為與 ROUND_HALF_UP 相同筐付;如果為偶數(shù),則舍入行為與 ROUND_HALF_DOWN 相同阻肿。注意:在重復(fù)進行一系列計算時,此舍入模式可以將累加錯誤減到最小沮尿。此舍入模式也稱為“銀行家舍入法”丛塌,主要在美國使用。四舍六入畜疾,五分兩種情況赴邻,如果前一位為奇數(shù),則入位啡捶,否則舍去姥敛。

ROUND_UNNECESSARY :斷言請求的操作具有精確的結(jié)果,因此不需要舍入瞎暑。如果對獲得精確結(jié)果的操作指定此舍入模式彤敛,則拋出ArithmeticException。

按照各自的需要了赌,可傳入合適的第三個參數(shù)墨榄。四舍五入采用 ROUND_HALF_UP

需要對BigDecimal進行截斷和四舍五入可用setScale方法,例:
更多請參考:https://www.cnblogs.com/Jason-Xiang/p/10220231.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勿她,一起剝皮案震驚了整個濱河市袄秩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逢并,老刑警劉巖之剧,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異砍聊,居然都是意外死亡背稼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門辩恼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雇庙,“玉大人谓形,你說我怎么就攤上這事〗埃” “怎么了寒跳?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長竹椒。 經(jīng)常有香客問我童太,道長,這世上最難降的妖魔是什么胸完? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任书释,我火速辦了婚禮,結(jié)果婚禮上赊窥,老公的妹妹穿的比我還像新娘爆惧。我一直安慰自己,他們只是感情好锨能,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布扯再。 她就那樣靜靜地躺著,像睡著了一般址遇。 火紅的嫁衣襯著肌膚如雪熄阻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天倔约,我揣著相機與錄音秃殉,去河邊找鬼。 笑死浸剩,一個胖子當著我的面吹牛钾军,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播乒省,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼巧颈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了袖扛?” 一聲冷哼從身側(cè)響起砸泛,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛆封,沒想到半個月后唇礁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡惨篱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年盏筐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砸讳。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡琢融,死狀恐怖界牡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情漾抬,我是刑警寧澤宿亡,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站纳令,受9級特大地震影響挽荠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜平绩,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一圈匆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧捏雌,春花似錦跃赚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至窘奏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間葫录,已是汗流浹背着裹。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留米同,地道東北人骇扇。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像面粮,于是被迫代替她去往敵國和親少孝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

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