需求
業務需要導出的Excel的數字內容保留兩位小數,并且四舍五入
代碼實現
百度一圈所抄襲的代碼
1
2
|
dfScale2.format( 1 .125D); |
發現問題
導出數據很詭異.不是所有數據都是如所想的四舍五入.
經過排查最終發現是RoundingMode的問題,應該使用HALF_UP,
DecimalFormat 默認使用的是HALF_EVEN
1
2
3
4
5
|
DecimalFormat dfScale2 = new DecimalFormat( "###.##" ); System.out.println( "dfScale2.getRoundingMode()=" + dfScale2.getRoundingMode()); //輸出結果 dfScale2.getRoundingMode()=HALF_EVEN // |
RoundingMode.HALF_EVEN
想了解HALF_EVEN,去官網API看了下
HALF_EVEN 被舍位是5(如保留兩位小數的2.115),后面還有非0值進1(如保留兩位小數的2.11500001 格式化為2.12),5后面沒有數字或者都是0時,前面是偶數則舍,是奇數則進1,目標是讓被舍前一位變為偶數.
- 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 設置這個模式,對于精確值格式化會拋出異常
- Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
- UP 向遠離數字0進行進位.
- Rounding mode to round away from zero.
錯誤的代碼測試RoundingMode.HALF_EVEN
為了更好的理解HALF_EVEN,寫了些測試代碼但是發現自己更迷惘了…搞不清楚到底HALF_EVEN是什么機制進舍…輸出結果的尾數很不規律.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.*; public class LocalTest { //定義一個保留兩位小數格式的 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)); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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
突然發現自己忽略了一個事情,測試的參數都是用的double類型.想起來double類型不精準.但是僥幸心理以及知識不牢靠以為 3位小數應該影響不大吧.改了下代碼,把參數改為BigDecimal類型
使用BigDecimal時,參數盡量傳入字符串,要比傳入double精準.
1
|
new BigDecimal( "1.125" ) |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@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" ))); |
1
2
3
4
5
6
7
8
9
10
|
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 |
結論
1、警覺doulbe的不精確所引起RoundingMode結果不穩定的問題,即使是四舍五入的模式,對double類型參數使用也會有不滿足預期的情況.
2、使用數字格式化時,要注意默認RoundingMode模式是否是自己需要的.如果不是記得手動設置下.
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/baixf/article/details/88792219