Java DecimalFormat四舍五入异常:14.3445格式化结果不符预期
嘿,这个问题其实藏着两个容易踩坑的点:浮点数精度限制和DecimalFormat默认的舍入规则,还有你对舍入逻辑的小误解,咱们一个个说清楚:
1. 你的分步舍入逻辑是错的
首先纠正一个认知:DecimalFormat不会像你想的那样先把14.3445转成14.345(三位小数),再转成14.35(两位小数)。它是直接对原始数值进行舍入,保留到指定的两位小数——也就是说,它会看第三位小数的数值及后面的部分,直接判断是否进位,不会做中间过渡步骤。
2. 14.3445作为double类型,并不是精确的14.3445
这是关键问题!十进制的14.3445无法用二进制浮点数(也就是Java里的double)精确表示,实际存储在内存里的是一个略小于14.3445的近似值。你可以用BigDecimal来打印这个精确值验证:
System.out.println(new BigDecimal(14.3445));
输出大概是:
14.3444999999999994315658113919198513031005859375
看到没?这个实际值比14.3445还小一点,更别说达到14.345了。所以当你用DecimalFormat保留两位小数时,它处理的是这个近似值,自然会得到14.34。
3. DecimalFormat默认用的是「银行家舍入法」
就算我们假设数值是精确的14.3445,DecimalFormat默认的舍入模式是RoundingMode.HALF_EVEN(银行家舍入法),不是我们日常用的「四舍五入」(RoundingMode.HALF_UP)。这种舍入规则是:如果舍去部分的最高位是5,且前一位是偶数,就舍去;如果前一位是奇数,才进位。不过在这个案例里,因为第三位小数是4,不管哪种舍入模式都会舍去,所以这一点不是这次问题的主要原因,但也是你需要了解的知识点。
怎么得到你预期的14.35?
要解决这个问题,你需要同时解决浮点数精度和舍入模式两个问题:
方法一:用BigDecimal存储精确的十进制数,再设置正确的舍入模式
// 用字符串创建BigDecimal,保证数值精确 BigDecimal num = new BigDecimal("14.3445"); DecimalFormat df2 = new DecimalFormat(".00"); // 设置为传统四舍五入模式 df2.setRoundingMode(RoundingMode.HALF_UP); System.out.println(df2.format(num)); // 输出14.35
方法二:直接用BigDecimal的setScale方法
如果不需要格式化字符串,只是需要数值计算后的结果,直接用BigDecimal的舍入更简单:
BigDecimal num = new BigDecimal("14.3445"); BigDecimal result = num.setScale(2, RoundingMode.HALF_UP); System.out.println(result); // 输出14.35
内容的提问来源于stack exchange,提问作者xMilos

