java.text.DecimalFormat使用###0.00%格式的舍入差异问题
关于
java.text.DecimalFormat ###0.00%格式舍入差异的解释 核心原因:二进制浮点数的精度偏差
你遇到的差异本质是十进制小数无法被二进制浮点数精确表示导致的。像0.012350和0.014350这类十进制值,在Java的double/float类型中存储的是近似值:
0.012350 * 100的实际存储值是1.234999999999999988...(略小于1.2350)0.014350 * 100的实际存储值是1.435000000000000106...(略大于1.4350)
这种微小偏差直接影响了HALF_EVEN(银行家舍入)的判断逻辑。
HALF_EVEN舍入的实际应用逻辑
HALF_EVEN舍入的规则是:当需要舍弃的部分最高位为5,且后续没有非零数字时,看保留部分的最后一位:
- 若为偶数,则舍弃多余部分;
- 若为奇数,则向前进1。
但因为实际存储的数值不是精确的1.2350和1.4350:
- 对于
1.234999...,要保留两位小数时,第三位有效数字是4(而非5),直接舍弃,最终得到1.23%; - 对于
1.435000...,第三位有效数字是5,且前一位是3(奇数),触发进位,最终得到1.44%。
DigitList中hasBeenRoundedUp的作用
DigitList是DecimalFormat内部处理数字各位的核心类,hasBeenRoundedUp标记用于控制舍入的连锁反应:
- 当某次舍入操作触发进位(比如低位舍入导致前一位加1),
hasBeenRoundedUp会被设为true; - 后续处理更低位的数字时,会直接截断而非再次判断舍入,避免因进位后数值变化引发重复舍入,保证格式化过程的稳定性和结果的一致性。比如如果进位后某一位变成10需要继续进位,这个标记会确保只处理一次进位逻辑,防止无限循环。
内容的提问来源于stack exchange,提问作者Gautham M
相关产品推荐
相关产品推荐

