Java 的 Bigdecimal.divide and rounding

2022-09-01 09:54:49

在工作中,我们在尝试将大数字除以1000时发现了一个问题。此数字来自数据库。

假设我有这个方法:

private static BigDecimal divideBy1000(BigDecimal dividendo) {
    if (dividendo == null) return null;

    return dividendo.divide(BigDecimal.valueOf(1000), RoundingMode.HALF_UP);
}

当我拨打以下电话时

divideBy1000(new BigDecimal("176100000"))

我收到预期值 176100。但是,如果我尝试下面的行

divideBy1000(new BigDecimal("1761e+5"))

我收到值 200000。为什么会发生这种情况?这两个数字是相同的,表示形式不同,最新的是我从数据库中收到的。我明白,不知何故,JVM将数字1761除以1000,向上舍入并在末尾填充0。

避免这种行为的最佳方法是什么?请记住,原始号码不受我的控制。


答案 1

如 javadoc 中所指定,a 由整数值和小数位数定义。BigDecimal

因此,由 BigDecimal 表示的数字的值为 (unscaledValue × 10^(-scale))。

比例尺 -5 和比例尺 0 也是如此。BigDecimal("1761e+5")BigDecimal(176100000)

两者的除法分别使用 -5 和 0 刻度完成,因为在除法时未指定刻度。除法文档解释了为什么结果不同。BigDecimal

divide

public BigDecimal divide(BigDecimal divisor)

返回一个大十进制数,其值为 ,其首选刻度为 ;如果无法表示确切的商(因为它具有非终止十进制展开),则抛出 。(this / divisor)(this.scale() - divisor.scale())ArithmeticException

参数:

divisor- 此大十进制值的除法值。

返回:

this / divisor

抛出:

算术异常 — 如果精确商没有终止十进制展开

因为:

1.5

如果您在除法时指定比例,例如 你会得到同样的结果。dividendo.divide(BigDecimal.valueOf(1000), 0, RoundingMode.HALF_UP)


答案 2

表达式和不相等。 跟踪价值和精度。new BigDecimal("176100000")new BigDecimal("1761e+5")BigDecimal

BigDecimal("176100000")具有 9 位精度,在内部表示为 乘以 1。 具有 4 位精度,在内部表示为 乘以 100000。BigInteger("176100000")BigDecimal("1761e+5")BigInteger("1761")

将 a 除以值时,结果将遵循精度的数字,从而为看似相等的值生成不同的输出。BigDecimal


推荐