You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RoundingMode.FLOOR模式下BigDecimal与DecimalFormat舍入结果不一致问题

// 问题复现代码
BigDecimal bd = new BigDecimal(-0.0009).setScale(0, RoundingMode.FLOOR);
System.out.println(bd.toPlainString()); // 输出-1

DecimalFormat df = new DecimalFormat("0");
df.setRoundingMode(RoundingMode.FLOOR);
System.out.println(df.format(-0.0009)); // 输出-0
差异原因

RoundingMode.FLOOR的官方定义是向负无穷方向舍入,-0.0009介于-1和0之间,向负无穷舍入的正确结果应为-1,BigDecimal的输出完全符合规范。
DecimalFormat输出-0是其内部实现逻辑导致的:

  • 它在应用舍入规则前,会先根据设置的格式模式的小数位数,对输入值做预精度截断。当使用0、0.0、0.00这类小数位少于3的模式时,-0.0009会被先近似识别为-0,后续对-0应用FLOOR舍入时,输出结果仍为-0。
  • 当使用0.000模式时,小数位为3位,-0.0009不会被预截断为-0,会保留足够精度参与舍入,因此能得到符合预期的结果。
解决方案
  • 方案1:优先使用BigDecimal完成舍入逻辑,再将舍入后的结果传给DecimalFormat格式化,规避DecimalFormat的内部逻辑问题,示例代码:
BigDecimal bd = new BigDecimal("-0.0009").setScale(0, RoundingMode.FLOOR);
DecimalFormat df = new DecimalFormat("0");
System.out.println(df.format(bd)); // 输出-1,符合预期
  • 方案2:若必须使用DecimalFormat的舍入能力,需开启setParseBigDecimal配置,且传入字符串构造的BigDecimal类型参数,避免double精度丢失和预截断问题,示例代码:
DecimalFormat df = new DecimalFormat("0");
df.setRoundingMode(RoundingMode.FLOOR);
df.setParseBigDecimal(true);
System.out.println(df.format(new BigDecimal("-0.0009"))); // 输出-1,符合预期

注意:直接用double值构造BigDecimal存在精度丢失风险,推荐优先使用字符串形式的构造方法传入精确数值。

内容的提问来源于stack exchange,提问作者Tyronne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 10:57:02