Java DecimalFormat 保留小數(shù)位及四舍五入的陷阱介紹
需求
業(yè)務(wù)需要導(dǎo)出的Excel的數(shù)字內(nèi)容保留兩位小數(shù),并且四舍五入
代碼實(shí)現(xiàn)
百度一圈所抄襲的代碼
DecimalFormat dfScale2 = new DecimalFormat("###.##"); dfScale2.format(1.125D);
發(fā)現(xiàn)問(wèn)題
導(dǎo)出數(shù)據(jù)很詭異.不是所有數(shù)據(jù)都是如所想的四舍五入.
經(jīng)過(guò)排查最終發(fā)現(xiàn)是RoundingMode的問(wèn)題,應(yīng)該使用HALF_UP,
DecimalFormat 默認(rèn)使用的是HALF_EVEN
DecimalFormat dfScale2 = new DecimalFormat("###.##"); System.out.println("dfScale2.getRoundingMode()=" + dfScale2.getRoundingMode()); //輸出結(jié)果 dfScale2.getRoundingMode()=HALF_EVEN //
RoundingMode.HALF_EVEN
想了解HALF_EVEN,去官網(wǎng)API看了下
HALF_EVEN 被舍位是5(如保留兩位小數(shù)的2.115),后面還有非0值進(jìn)1(如保留兩位小數(shù)的2.11500001 格式化為2.12),5后面沒(méi)有數(shù)字或者都是0時(shí),前面是偶數(shù)則舍,是奇數(shù)則進(jìn)1,目標(biāo)是讓被舍前一位變?yōu)榕紨?shù).
- CEILING 向更大的值靠近
- Rounding mode to round towards positive infinity.
- DOWN向下取整
- Rounding mode to round towards zero.
- FLOOR 向更小的值靠近
- Rounding mode to round towards negative infinity.
- HALF_DOWN 五舍六入
- Rounding mode to round towards “nearest neighbor” unless both neighbors are equidistant, in which case round down.
- HALF_EVEN
- Rounding mode to round towards the “nearest neighbor” unless both neighbors are equidistant, in which case, round towards the even neighbor.
- HALF_UP 四舍五入
- Rounding mode to round towards “nearest neighbor” unless both neighbors are equidistant, in which case round up.
- UNNECESSARY 設(shè)置這個(gè)模式,對(duì)于精確值格式化會(huì)拋出異常
- Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
- UP 向遠(yuǎn)離數(shù)字0進(jìn)行進(jìn)位.
- Rounding mode to round away from zero.
錯(cuò)誤的代碼測(cè)試RoundingMode.HALF_EVEN
為了更好的理解HALF_EVEN,寫(xiě)了些測(cè)試代碼但是發(fā)現(xiàn)自己更迷惘了…搞不清楚到底HALF_EVEN是什么機(jī)制進(jìn)舍…輸出結(jié)果的尾數(shù)很不規(guī)律.
import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.*; public class LocalTest { //定義一個(gè)保留兩位小數(shù)格式的 DecimalFormat 的變量 dfScale2 @Test public void testDecimalFormat() { DecimalFormat dfScale2 = new DecimalFormat("###.##"); System.out.println("dfScale2.getRoundingMode()=" + dfScale2.getRoundingMode()); System.out.println("dfScale2.format(1.125D)=" + dfScale2.format(1.125D)); System.out.println("dfScale2.format(1.135D)=" + dfScale2.format(1.135D)); System.out.println("dfScale2.format(1.145D)=" + dfScale2.format(1.145D)); System.out.println("dfScale2.format(1.225D)=" + dfScale2.format(1.225D)); System.out.println("dfScale2.format(1.235D)=" + dfScale2.format(1.235D)); System.out.println("dfScale2.format(1.245D)=" + dfScale2.format(1.245D)); System.out.println(); System.out.println("dfScale2.format(2.125D)=" + dfScale2.format(2.125D)); System.out.println("dfScale2.format(2.135D)=" + dfScale2.format(2.135D)); System.out.println("dfScale2.format(2.145D)=" + dfScale2.format(2.145D)); System.out.println("dfScale2.format(2.225D)=" + dfScale2.format(2.225D)); System.out.println("dfScale2.format(2.235D)=" + dfScale2.format(2.235D)); System.out.println("dfScale2.format(2.245D)=" + dfScale2.format(2.245D)); System.out.println(); System.out.println("dfScale2.format(3.125D)=" + dfScale2.format(3.125D)); System.out.println("dfScale2.format(3.135D)=" + dfScale2.format(3.135D)); System.out.println("dfScale2.format(3.145D)=" + dfScale2.format(3.145D)); System.out.println("dfScale2.format(3.225D)=" + dfScale2.format(3.225D)); System.out.println("dfScale2.format(3.235D)=" + dfScale2.format(3.235D)); System.out.println("dfScale2.format(3.245D)=" + dfScale2.format(3.245D)); System.out.println(); System.out.println("dfScale2.format(4.125D)=" + dfScale2.format(4.125D)); System.out.println("dfScale2.format(4.135D)=" + dfScale2.format(4.135D)); System.out.println("dfScale2.format(4.145D)=" + dfScale2.format(4.145D)); System.out.println("dfScale2.format(4.225D)=" + dfScale2.format(4.225D)); System.out.println("dfScale2.format(4.235D)=" + dfScale2.format(4.235D)); System.out.println("dfScale2.format(4.245D)=" + dfScale2.format(4.245D)); } }
dfScale2.getRoundingMode()=HALF_EVEN dfScale2.format(1.125D)=1.12 dfScale2.format(1.135D)=1.14 dfScale2.format(1.145D)=1.15 dfScale2.format(1.225D)=1.23 dfScale2.format(1.235D)=1.24 dfScale2.format(1.245D)=1.25 dfScale2.format(2.125D)=2.12 dfScale2.format(2.135D)=2.13 dfScale2.format(2.145D)=2.15 dfScale2.format(2.225D)=2.23 dfScale2.format(2.235D)=2.23 dfScale2.format(2.245D)=2.25 dfScale2.format(3.125D)=3.12 dfScale2.format(3.135D)=3.13 dfScale2.format(3.145D)=3.15 dfScale2.format(3.225D)=3.23 dfScale2.format(3.235D)=3.23 dfScale2.format(3.245D)=3.25 dfScale2.format(4.125D)=4.12 dfScale2.format(4.135D)=4.13 dfScale2.format(4.145D)=4.14 dfScale2.format(4.225D)=4.22 dfScale2.format(4.235D)=4.24 dfScale2.format(4.245D)=4.25
正確的代碼測(cè)試RoundingMode.HALF_EVEN
突然發(fā)現(xiàn)自己忽略了一個(gè)事情,測(cè)試的參數(shù)都是用的double類型.想起來(lái)double類型不精準(zhǔn).但是僥幸心理以及知識(shí)不牢靠以為 3位小數(shù)應(yīng)該影響不大吧.改了下代碼,把參數(shù)改為BigDecimal類型
使用BigDecimal時(shí),參數(shù)盡量傳入字符串,要比傳入double精準(zhǔn).
new BigDecimal("1.125")
@Test public void testDecimalFormat() { DecimalFormat dfScale2 = new DecimalFormat("###.##"); dfScale2.setRoundingMode(RoundingMode.HALF_EVEN); System.out.println("dfScale2.getRoundingMode()=" + dfScale2.getRoundingMode()); System.out.println("dfScale2.format(new BigDecimal(\"1.1251\"))=" + dfScale2.format(new BigDecimal("1.1251"))); System.out.println("dfScale2.format(new BigDecimal(\"1.1351\"))=" + dfScale2.format(new BigDecimal("1.1351"))); System.out.println("dfScale2.format(new BigDecimal(\"1.1451\"))=" + dfScale2.format(new BigDecimal("1.1451"))); System.out.println("dfScale2.format(new BigDecimal(\"1.2250\"))=" + dfScale2.format(new BigDecimal("1.2250"))); System.out.println("dfScale2.format(new BigDecimal(\"1.2350\"))=" + dfScale2.format(new BigDecimal("1.2350"))); System.out.println("dfScale2.format(new BigDecimal(\"1.2450\"))=" + dfScale2.format(new BigDecimal("1.2450"))); System.out.println("dfScale2.format(new BigDecimal(\"1.22501\"))=" + dfScale2.format(new BigDecimal("1.22501"))); System.out.println("dfScale2.format(new BigDecimal(\"1.23505\"))=" + dfScale2.format(new BigDecimal("1.23505"))); System.out.println("dfScale2.format(new BigDecimal(\"1.24508\"))=" + dfScale2.format(new BigDecimal("1.24508")));
dfScale2.getRoundingMode()=HALF_EVEN dfScale2.format(new BigDecimal("1.1251"))=1.13 dfScale2.format(new BigDecimal("1.1351"))=1.14 dfScale2.format(new BigDecimal("1.1451"))=1.15 dfScale2.format(new BigDecimal("1.2250"))=1.22 dfScale2.format(new BigDecimal("1.2350"))=1.24 dfScale2.format(new BigDecimal("1.2450"))=1.24 dfScale2.format(new BigDecimal("1.22501"))=1.23 dfScale2.format(new BigDecimal("1.23505"))=1.24 dfScale2.format(new BigDecimal("1.24508"))=1.25
結(jié)論
1、警覺(jué)doulbe的不精確所引起RoundingMode結(jié)果不穩(wěn)定的問(wèn)題,即使是四舍五入的模式,對(duì)double類型參數(shù)使用也會(huì)有不滿足預(yù)期的情況.
2、使用數(shù)字格式化時(shí),要注意默認(rèn)RoundingMode模式是否是自己需要的.如果不是記得手動(dòng)設(shè)置下.
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
JFrame中添加和設(shè)置JPanel的方法實(shí)例解析
這篇文章主要介紹了JFrame中添加和設(shè)置JPanel的方法實(shí)例解析,具有一定借鑒價(jià)值2018-01-01JAVA實(shí)現(xiàn)簡(jiǎn)單搶紅包算法(模擬真實(shí)搶紅包)
這篇文章主要介紹了JAVA實(shí)現(xiàn)簡(jiǎn)單搶紅包算法(模擬真實(shí)搶紅包)的實(shí)例代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-12-12SpringBoot整合Ureport2報(bào)表及常見(jiàn)使用方法
這篇文章主要介紹了SpringBoot整合Ureport2報(bào)表及常見(jiàn)使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01