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

Java NumberFormat的UP舍入模式异常,测试用例失败咨询

问题根源:Double的精度缺失导致UP舍入未按预期工作

你并没有误用UP舍入模式——这个模式确实会向远离零的方向舍入所有非零的舍弃部分。问题出在你使用的Double类型无法精确表示0.01这个数值,这才导致了不符合预期的格式化结果。

为什么会这样?

当你执行1 / 100.toDouble()时,得到的并不是精确的0.01,而是一个略小于0.01的近似值(具体是0.009999999999999998)。虽然调试时IDE可能显示为0.01,但底层存储的是这个不精确的二进制浮点值。

当NumberFormat处理这个近似值时,它看到的是一个接近0但还没到0.01的数。结合maximumFractionDigits = 0的设置,UP舍入模式会检查小数点后的部分:由于这个近似值的小数点后第一位是0(实际值是0.009999...),舍入逻辑并没有触发向整数位的进位,最终输出了$0。

解决方案:使用BigDecimal保证数值精确

要解决这个问题,你需要用BigDecimal来精确表示0.01,而不是依赖Double的近似值。修改后的测试用例如下:

@Test fun testFormatRoundedUp() { 
    val formatter = NumberFormat.getCurrencyInstance() 
    formatter.maximumFractionDigits = 0 
    formatter.roundingMode = RoundingMode.UP 
    formatter.currency = Currency.getInstance("USD") 
    // 使用BigDecimal精确表示0.01,避免Double精度问题
    val decimal = BigDecimal("0.01")
    assertThat(formatter.format(decimal)).isEqualTo("$1") 
}

额外验证:非货币格式化的情况

如果你不用货币格式化,同样的精度问题也会存在。比如用普通的NumberFormat格式化Double类型的0.01,也会得到0;但用BigDecimal就会得到预期的1:

val formatter = NumberFormat.getInstance()
formatter.maximumFractionDigits = 0
formatter.roundingMode = RoundingMode.UP
// Double版本输出0
println(formatter.format(0.01))
// BigDecimal版本输出1
println(formatter.format(BigDecimal("0.01")))

总结一下:你的UP舍入模式用法是正确的,问题完全源于Double的浮点精度限制。改用BigDecimal精确表示小数后,就能得到你想要的舍入结果了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:12:08