Java?BigDecimal與RoundingMode最常用的用法總結(jié)
一、引進(jìn)
做算法題的時(shí)候,最氣人的不是不會(huì)寫(xiě),而是會(huì)寫(xiě)卻算錯(cuò)。明明邏輯滿分,一輸出“0.30000000000000004”,瞬間被判死刑。別懷疑,就是 double 在背后捅刀——它眼里 0.1+0.2 永遠(yuǎn)不等于 0.3。
想甩掉這坑,只能把 double 踢下線,讓 BigDecimal 上崗。它不講二進(jìn)制那一套,就按我們十進(jìn)制算盤(pán)打,指哪打哪,小數(shù)點(diǎn)后面想留幾位就留幾位,永遠(yuǎn)對(duì)得上賬。只要內(nèi)存夠,它能跟你耗到你先倒下,而且精度一分不差。
面對(duì)涉及金融計(jì)算、超大整數(shù)、或者需要絕對(duì)精確小數(shù)運(yùn)算的題目時(shí),
使用 BigDecimal
二、優(yōu)點(diǎn)
1.算得準(zhǔn)
double 眼里 0.1 其實(shí)是“0.100000000000000005…”,攢多了就翻車(chē)。BigDecimal 把數(shù)字當(dāng)“字符串”存,小學(xué)豎式怎么算它就怎么算,說(shuō) 0.1 就 0.1,一分不差。
2. 數(shù)字再大也裝得下
long 最大才 9 后面 18 個(gè)數(shù)字,題目動(dòng)不動(dòng)就要算 100 位的階乘?BigDecimal 直接把數(shù)字當(dāng)“無(wú)限長(zhǎng)”的數(shù)組,只要內(nèi)存不炸,它就能一直寫(xiě)下去。
3. 想怎么四舍五入你說(shuō)了算
題目要“保留兩位小數(shù)”“銀行家舍入”“直接砍尾”?一行 setScale+RoundingMode,分分鐘切好,double 卻只能干瞪眼。
4. 絕不溢出
int、long 加著加著變負(fù)數(shù)?放心,BigDecimal 只要內(nèi)存有多大,我就能算多大。
三、算法題中最常用的BigDecimal方法
構(gòu)造方法:
BigDecimal(String val): 最推薦、最安全的方式! 使用字符串構(gòu)造可以精確表示你想要的數(shù)值
(如 new BigDecimal(“0.1”))。避免使用BigDecimal(double val),因?yàn)閭魅氲膁ouble本身可能已有精度損失(如 new BigDecimal(0.1) 實(shí)際上構(gòu)造的是
0.1000000000000000055511151231257827021181583404541015625)。
BigDecimal.valueOf(double val): 這是將double轉(zhuǎn)換為BigDecimal的相對(duì)安全方式。它內(nèi)部調(diào)用Double.toString(double),利用了字符串轉(zhuǎn)換的精確性。適用于已知double值能精確表示或精度要求高的場(chǎng)景(比直接使用double構(gòu)造器好得多)。
算術(shù)運(yùn)算:
add(BigDecimal augend): 加法
subtract(BigDecimal subtrahend): 減法
multiply(BigDecimal multiplicand): 乘法
divide(BigDecimal divisor): 除法
(注意: 如果結(jié)果無(wú)法精確表示(如1 / 3),會(huì)拋出ArithmeticException,必須指定舍入模式?。?divide(BigDecimal divisor, int scale, RoundingMode roundingMode): 最常用的除法形式!
指定結(jié)果的小數(shù)位數(shù)(scale)和舍入模式(roundingMode)。
divide(BigDecimal divisor, RoundingMode roundingMode): 除法,使用指定的舍入模式,結(jié)果精度由計(jì)算決定(通常位數(shù)較多)
abs(): 絕對(duì)值
pow(int n): 冪運(yùn)算(n次方)
比較:
compareTo(BigDecimal val): 比較大小的標(biāo)準(zhǔn)方法
返回 -1(小于)、0(等于)、1(大于)。必須使用此方法代替equals()!
重要陷阱: equals()方法不僅比較數(shù)值是否相等,還比較精度(scale)是否相同。
new BigDecimal(“1.0”).equals(new BigDecimal(“1.00”)) 會(huì)返回 false!
而compareTo() 只關(guān)心數(shù)值本身,1.0和1.00比較結(jié)果為0(相等)。
精度控制與舍入:
setScale(int newScale, RoundingMode roundingMode): 核心精度控制方法! 設(shè)置小數(shù)點(diǎn)后的位數(shù)(newScale),并使用指定的RoundingMode進(jìn)行必要的舍入操作。
如果當(dāng)前scale大于newScale,需要舍入; 如果小于newScale,則在末尾補(bǔ)零。
scale(): 獲取當(dāng)前小數(shù)點(diǎn)后的位數(shù)。
輸出:
toString():
返回此BigDecimal的規(guī)范字符串表示形式。如果需要特定格式(如固定小數(shù)位、科學(xué)計(jì)數(shù)法),應(yīng)使用NumberFormat或DecimalFormat。
toPlainString():
返回不帶指數(shù)字段的字符串表示。對(duì)于非常大或非常小的數(shù),toString()可能輸出科學(xué)計(jì)數(shù)法(如1e+10),而toPlainString()會(huì)輸出"10000000000"。
四、RoundingMode:定義如何“舍”與“入”
RoundingMode是一個(gè)枚舉類(lèi)(java.math.RoundingMode),定義了8種舍入策略。它與BigDecimal的divide和setScale方法緊密結(jié)合,是精確控制結(jié)果的關(guān)鍵。算法競(jìng)賽中最常用的幾種模式:
RoundingMode.HALF_UP (“四舍五入”):
- 規(guī)則: 舍棄部分 >= 0.5 時(shí)進(jìn)位;< 0.5 時(shí)舍棄。
- 例子: 5.5 -> 6, 2.5 -> 3, 1.4 -> 1, 1.6 -> 2
- 諧音:“哈夫上”
畫(huà)面:哈(HALF)佛老教授走上(UP)講臺(tái)——只上一半臺(tái)階就回頭,“過(guò)半就上去”。 - 競(jìng)賽應(yīng)用: 題目明確要求“四舍五入”時(shí)使用。這是最符合直覺(jué)的舍入方式。
RoundingMode.DOWN (“向零舍入”):
- 規(guī)則: 無(wú)論舍棄部分大小,總是向零的方向舍入(即絕對(duì)值變小)。
- 例子: 5.9 -> 5, -5.9 -> -5, 1.1 -> 1, -1.1 -> -1
- 諧音:“剁”
畫(huà)面:一把刀剁下去,向零剁,數(shù)字瞬間被砍到 0 那邊。 - 競(jìng)賽應(yīng)用: 需要截?cái)嘈?shù)部分(取整)而不進(jìn)行任何舍入時(shí)使用。類(lèi)似于強(qiáng)制類(lèi)型轉(zhuǎn)換(int)的效果。
RoundingMode.CEILING (“向正無(wú)窮舍入”):
- 規(guī)則: 結(jié)果總是向正無(wú)窮方向舍入(向上取整)。
- 例子: 5.1 -> 6, -5.1 -> -5, 1.0 -> 1
- 競(jìng)賽應(yīng)用: 需要計(jì)算“至少需要多少個(gè)”的場(chǎng)景(如物品裝箱、資源分配)。
RoundingMode.FLOOR (“向負(fù)無(wú)窮舍入”):
- 規(guī)則: 結(jié)果總是向負(fù)無(wú)窮方向舍入(向下取整)。
- 例子: 5.9 -> 5, -5.9 -> -6, 1.0 -> 1
- 競(jìng)賽應(yīng)用: 需要計(jì)算“最多能容納多少個(gè)”的場(chǎng)景。
RoundingMode.HALF_EVEN (“銀行家舍入法”):
- 規(guī)則: 舍棄部分 > 0.5 時(shí)進(jìn)位;< 0.5 時(shí)舍棄;等于 0.5 時(shí),看前一位數(shù)字:如果是奇數(shù)則進(jìn)位,如果是偶數(shù)則舍棄。
- 例子: 5.5 -> 6 (5是奇數(shù),進(jìn)位), 2.5 -> 2 (2是偶數(shù),舍棄), 1.6 -> 2, 1.4 -> 1
- 競(jìng)賽應(yīng)用: 在統(tǒng)計(jì)學(xué)或需要減少累計(jì)誤差的場(chǎng)景中更優(yōu)。題目沒(méi)有特別說(shuō)明“四舍五入”時(shí),有時(shí)會(huì)默認(rèn)使用此規(guī)則(需仔細(xì)審題!)
五、在算法題中使用BigDecimal的典型流程
構(gòu)造:
優(yōu)先使用String構(gòu)造或BigDecimal.valueOf()運(yùn)算:
使用add, subtract, multiply進(jìn)行基本運(yùn)算。進(jìn)行divide時(shí),一定要指定精度(scale)和舍入模式(RoundingMode)!精度控制:
在最終輸出結(jié)果前,使用setScale(int desiredScale, RoundingMode roundingMode)將 結(jié)果調(diào)整到題目要求的精度。比較:
使用compareTo()比較兩個(gè)BigDecimal的大小。輸出:
使用toString()或toPlainString()輸出,或者根據(jù)題目要求使用格式化輸出。
例題
計(jì)算圓的面積,保留兩位小數(shù),四舍五入
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Scanner;
public class CircleArea {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
BigDecimal radius = new BigDecimal(sc.nextDouble());
BigDecimal PI = new BigDecimal("3.14159");
//計(jì)算面積
BigDecimal area = PI.multiply(radius).multiply(radius);
//設(shè)置精度,保留兩位小數(shù),四舍五入
area = area.setScale(2,RoundingMode.HALF_UP);
System.out.println(area);
//輸入:5.0
//輸出:78.54
}
}
總結(jié)
到此這篇關(guān)于Java BigDecimal與RoundingMode最常用用法的文章就介紹到這了,更多相關(guān)Java BigDecimal與RoundingMode用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中BigDecimal與0比較的一個(gè)坑實(shí)戰(zhàn)記錄
BigDecimal屬于大數(shù)據(jù),精度極高,不屬于基本數(shù)據(jù)類(lèi)型,屬于java對(duì)象,下面這篇文章主要給大家介紹了關(guān)于Java中BigDecimal與0比較的一個(gè)坑的相關(guān)資料,需要的朋友可以參考下2022-12-12
JavaFX桌面應(yīng)用未響應(yīng)問(wèn)題解決方案
這篇文章主要介紹了JavaFX桌面應(yīng)用未響應(yīng)問(wèn)題解決方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
java使用EasyExcel導(dǎo)出上萬(wàn)數(shù)據(jù)如何避免OOM
本文主要介紹了使用EasyExcel導(dǎo)出大量數(shù)據(jù)時(shí)避免OOM問(wèn)題的方法,通過(guò)分頁(yè)查詢和分批次寫(xiě)入Excel,可以有效避免內(nèi)存溢出,并提供了一個(gè)封裝好的工具類(lèi),簡(jiǎn)化了導(dǎo)出代碼的編寫(xiě)2024-11-11
Java 根據(jù)某個(gè) key 加鎖的實(shí)現(xiàn)方式
日常開(kāi)發(fā)中,有時(shí)候需要根據(jù)某個(gè) key 加鎖,確保多線程情況下,對(duì)該 key 的加鎖和解鎖之間的代碼串行執(zhí)行,這篇文章主要介紹了Java 根據(jù)某個(gè) key 加鎖的實(shí)現(xiàn)方式,需要的朋友可以參考下2023-03-03
基于synchronized修飾靜態(tài)和非靜態(tài)方法
這篇文章主要介紹了基于synchronized修飾靜態(tài)和非靜態(tài)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
Java中遍歷ConcurrentHashMap的四種方式詳解
這篇文章主要介紹了Java中遍歷ConcurrentHashMap的四種方式詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10

