Java DecimalFormat保留1位小数时9.85与9.95舍入结果不一致问题
问题核心原因
你遇到的不一致表现是两个因素共同导致的:double类型的浮点数精度丢失,以及DecimalFormat默认的舍入模式规则。
1. 浮点数精度问题
Java中9.85、9.95这类直接写的字面量默认是double类型,属于二进制浮点数,无法精确表示所有十进制小数,你以为传入的是精确的十进制值,实际JVM存储的值和预期有偏差:
- 你写的
9.85实际存储的double值约为9.8499999999999996447286321199499070644378662109375,比真实的9.85略小 - 你写的
9.95实际存储的double值约为9.9500000000000010658141036401502788066864013671875,比真实的9.95略大
你可以直接用System.out.println(new BigDecimal(9.85))打印验证实际存储的数值。
2. DecimalFormat默认舍入规则
DecimalFormat默认使用RoundingMode.HALF_EVEN(银行家舍入法),规则为:
- 当舍去部分的最高位小于5时直接舍去
- 当舍去部分的最高位大于5时向前一位进1
- 当舍去部分的最高位恰好是5时,若前一位是偶数则舍去,是奇数则进1
对应测试用例的解释
- 用例1:
new DecimalFormat("#.#").format(9.85)
传入的实际值略小于9.85,保留1位小数时舍去部分不足0.05,所以直接舍去得到9.8 - 用例2:
new DecimalFormat("#.#").format(9.86)
9.86的double存储值和真实值偏差极小,舍去部分大于0.05,触发进1得到9.9 - 用例3:
new DecimalFormat("#.#").format(9.95)
传入的实际值略大于9.95,保留1位小数时舍去部分大于0.05,触发进1,9.9+0.1等于10,最终输出10 - 用例4:
new DecimalFormat("#.#").format(9.96)
数值本身足够大,进1后得到10,符合预期
解决方案
如果要完全避免浮点数精度带来的舍入异常,建议不要直接传入double类型做格式化,改用BigDecimal传递精确的十进制值,同时明确指定你需要的舍入模式:
// 示例:指定四舍五入模式,使用字符串构造BigDecimal保证精度 DecimalFormat df = new DecimalFormat("#.#"); df.setRoundingMode(RoundingMode.HALF_UP); // 明确设置为普通四舍五入模式 String res1 = df.format(new BigDecimal("9.85")); // 输出9.9 String res2 = df.format(new BigDecimal("9.95")); // 输出10.0
内容的提问来源于stack exchange,提问作者Pranesh Sahu
相关产品推荐
相关产品推荐

