Java DecimalFormat 保留小數(shù)位及四舍五入的陷阱介紹
需求
業(yè)務(wù)需要導出的Excel的數(shù)字內(nèi)容保留兩位小數(shù),并且四舍五入
代碼實現(xiàn)
百度一圈所抄襲的代碼
DecimalFormat dfScale2 = new DecimalFormat("###.##");
dfScale2.format(1.125D);
發(fā)現(xiàn)問題
導出數(shù)據(jù)很詭異.不是所有數(shù)據(jù)都是如所想的四舍五入.
經(jīng)過排查最終發(fā)現(xiàn)是RoundingMode的問題,應(yīng)該使用HALF_UP,
DecimalFormat 默認使用的是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值進1(如保留兩位小數(shù)的2.11500001 格式化為2.12),5后面沒有數(shù)字或者都是0時,前面是偶數(shù)則舍,是奇數(shù)則進1,目標是讓被舍前一位變?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è)置這個模式,對于精確值格式化會拋出異常
- Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
- UP 向遠離數(shù)字0進行進位.
- Rounding mode to round away from zero.
錯誤的代碼測試RoundingMode.HALF_EVEN
為了更好的理解HALF_EVEN,寫了些測試代碼但是發(fā)現(xiàn)自己更迷惘了…搞不清楚到底HALF_EVEN是什么機制進舍…輸出結(jié)果的尾數(shù)很不規(guī)律.
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
public class LocalTest {
//定義一個保留兩位小數(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
正確的代碼測試RoundingMode.HALF_EVEN
突然發(fā)現(xiàn)自己忽略了一個事情,測試的參數(shù)都是用的double類型.想起來double類型不精準.但是僥幸心理以及知識不牢靠以為 3位小數(shù)應(yīng)該影響不大吧.改了下代碼,把參數(shù)改為BigDecimal類型
使用BigDecimal時,參數(shù)盡量傳入字符串,要比傳入double精準.
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、警覺doulbe的不精確所引起RoundingMode結(jié)果不穩(wěn)定的問題,即使是四舍五入的模式,對double類型參數(shù)使用也會有不滿足預期的情況.
2、使用數(shù)字格式化時,要注意默認RoundingMode模式是否是自己需要的.如果不是記得手動設(shè)置下.
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java優(yōu)先隊列(PriorityQueue)重寫compare操作
這篇文章主要介紹了Java優(yōu)先隊列(PriorityQueue)重寫compare操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10
淺談SpringMVC中Interceptor和Filter區(qū)別
這篇文章主要介紹了淺談SpringMVC中Interceptor和Filter區(qū)別,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04
SpringBoot事務(wù)鉤子函數(shù)的使用方式
本文介紹了SpringBoot中事務(wù)鉤子函數(shù)的使用方式,包括常見場景、使用方式等,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2024-11-11
Java編程實現(xiàn)基于圖的深度優(yōu)先搜索和廣度優(yōu)先搜索完整代碼
這篇文章主要介紹了Java編程實現(xiàn)基于圖的深度優(yōu)先搜索和廣度優(yōu)先搜索完整代碼,具有一定借鑒價值,需要的朋友可以了解下。2017-12-12
使用Java實現(xiàn)創(chuàng)建Excel表單控件
在數(shù)據(jù)填報時,創(chuàng)建Excel表單控件是一項常見的任務(wù),它可以極大地簡化數(shù)據(jù)收集和處理的過程,本文主要介紹了如何使用Java實現(xiàn)創(chuàng)建Excel表單控件,感興趣的可以了解下2024-03-03
Spring使用Redis限制用戶登錄失敗的次數(shù)及暫時鎖定用戶登錄權(quán)限功能
這篇文章主要介紹了Spring使用Redis限制用戶登錄失敗的次數(shù)及暫時鎖定用戶登錄權(quán)限功能,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2024-02-02

