为何DecimalFormat与String.format的HALF_UP舍入结果不一致?
为什么DecimalFormat和String.format的HALF_UP舍入结果不一致?
这是个很有意思的问题,核心原因藏在浮点数的精度特性以及两个API的内部处理逻辑差异里,咱们一步步拆解:
1. 先搞懂一个关键:double类型的3.55并不是精确值
二进制浮点数(比如Java里的double)没法精确表示所有十进制小数,3.55就是典型的例子。当你写double num = 3.55;时,JVM实际存储的是一个略小于3.55的近似值,具体来说是:
3.54999999999999982236431605997495353221893310546875
你可以用BigDecimal验证这个实际值:
BigDecimal bd = new BigDecimal(3.55); System.out.println(bd); // 输出上面的长串小数
2. DecimalFormat的处理逻辑
DecimalFormat是直接基于这个原始的近似double值来执行HALF_UP舍入的:
- 我们要保留1位小数,所以看第2位小数:这个近似值的第2位是4(3.549...)
- 按照HALF_UP规则,小于5就舍去,所以最终输出
3.5
3. String.format的处理逻辑
String.format("%.1f")的处理路径不一样:
- 它会先调用
Double.toString()把double值转换成最短的十进制字符串,这个字符串能唯一对应到该double值。对于存储的那个近似值来说,最短的十进制表示恰好就是3.55(因为这个近似值和3.55的差异小到超出了常规十进制的精度感知) - 然后再基于这个
3.55字符串执行HALF_UP舍入,第2位是5,所以进一位,得到3.6
如何让两者结果一致?
如果需要精确的十进制舍入,建议用BigDecimal来存储和处理数值,避免浮点数精度问题:
BigDecimal num = new BigDecimal("3.55"); // 用字符串构造保证精确 DecimalFormat df = new DecimalFormat("#0.0"); df.setRoundingMode(RoundingMode.HALF_UP); System.out.println(df.format(num)); // 输出3.6 System.out.println(String.format("%.1f", num)); // 输出3.6
内容的提问来源于stack exchange,提问作者joe
相关产品推荐
相关产品推荐

