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

