JAVADecimalFormat保留⼩数位以及四舍五⼊的陷阱
需求
业务需要导出的Excel的数字内容保留两位⼩数,并且四舍五⼊
代码实现
百度⼀圈所抄袭的代码
DecimalFormat dfScale2 =new DecimalFormat("###.##");
dfScale2.format(1.125D);
发现问题
导出数据很诡异.不是所有数据都是如所想的四舍五⼊.
经过排查最终发现是RoundingMode的问题,应该使⽤HALF_UP,
DecimalFormat 默认使⽤的是HALF_EVEN
DecimalFormat dfScale2 =new DecimalFormat("###.##");
System.out.println("RoundingMode()="+ RoundingMode());
//输出结果
//
RoundingMode.HALF_EVEN
CEILING 向更⼤的值靠近
Rounding mode to round towards positive infinity.
DOWN向下取整
Rounding mode to round towards zero.
FLOOR 向更⼩的值靠近
bigdecimal格式化两位小数
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是什么机制进舍…输出结果的尾数很不规律.
import java.math.BigDecimal;
import java.math.RoundingMode;
DecimalFormat;
import java.util.*;
public class LocalTest {
//定义⼀个保留两位⼩数格式的 DecimalFormat 的变量 dfScale2
@Test
public void testDecimalFormat(){
DecimalFormat dfScale2 =new DecimalFormat("###.##");
System.out.println("RoundingMode()="+ RoundingMode());
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.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精准.
new BigDecimal("1.125")
@Test
public void testDecimalFormat(){
DecimalFormat dfScale2 =new DecimalFormat("###.##");
dfScale2.setRoundingMode(RoundingMode.HALF_EVEN);
System.out.println("RoundingMode()="+ RoundingMode());
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.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模式是否是⾃⼰需要的.如果不是记得⼿动设置下.

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。