Java的Bigdecimal.divide和舍入

Rap*_*ale 26 java bigdecimal

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

说我有这个方法:

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

    return dividendo.divide(BigDecimal.valueOf(1000), RoundingMode.HALF_UP);
}
Run Code Online (Sandbox Code Playgroud)

当我拨打以下电话时

divideBy1000(new BigDecimal("176100000"))
Run Code Online (Sandbox Code Playgroud)

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

divideBy1000(new BigDecimal("1761e+5"))
Run Code Online (Sandbox Code Playgroud)

我收到价值200000.为什么会这样?这两个数字是相同的,具有不同的表示,最新的是我从数据库收到的.我知道,不知何故,JVM将数字1761除以1000,向上舍入并在最后填充0.

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

dce*_*chi 21

如javadoc中所指定的,a BigDecimal由整数值和比例定义.

因此,BigDecimal表示的数字的值是(unscaledValue×10 ^( - scale)).

因此,BigDecimal("1761e+5")具有规模经济-5和BigDecimal(176100000)有刻度0.

两者的划分BigDecimal分别使用-5和0标度来完成,因为在划分时没有指定标度.该divide文档解释了为什么结果是不同的.

divide

public BigDecimal divide(BigDecimal divisor)
Run Code Online (Sandbox Code Playgroud)

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

参数:

divisor - 要分割此BigDecimal的值.

返回:

this / divisor
Run Code Online (Sandbox Code Playgroud)

抛出:

ArithmeticException - 如果确切的商没有终止十进制扩展

以来:

1.5

如果在分割时指定刻度,例如,dividendo.divide(BigDecimal.valueOf(1000), 0, RoundingMode.HALF_UP)您将得到相同的结果.


Jos*_*hua 6

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

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

当您将a BigDecimal除以一个值时,结果会考虑精度的数字,从而导致看似相等的值的不同输出.

  • @Makoto:`compareTo`和`equals`与`BigDecimal`的操作不同. (6认同)

小智 6

使用 BigDecimal 进行除法。

dividendo.divide(divisor,2,RoundingMode.CEILING)//00.00 nothing for up and nothing for down
Run Code Online (Sandbox Code Playgroud)

在此操作中,精度为两位小数。