BigDecimal乘以零

Ric*_*ard 58 java rounding-error bigdecimal numerical-analysis

我正在使用BigDecimal进行简单的乘法运算,并且在乘以零时我发现了一些奇怪的行为(在这个用例中乘以零是正确的).

基本数学告诉我,任何乘以零的数字都将等于零(参见:零产品属性乘法属性)

但是,以下代码将始终失败并出现相同的错误:

assertEquals(new BigDecimal(0), new BigDecimal(22.3).multiply(new BigDecimal(0)));
Run Code Online (Sandbox Code Playgroud)
java.lang.AssertionError: 
Expected :0
Actual   :0E-48
Run Code Online (Sandbox Code Playgroud)

这是BigDecimal的不准确,还是我在某处遗漏了数学的一些利基分支?

注意:在IntelliJ 11中运行的JDK 1.6.0_27

Kep*_*pil 84

您不能使用该equals()方法进行比较BigDecimals,就像这个断言一样.那是因为这个等于函数会比较比例.如果比例不同,equals()则返回false,即使它们在数学上是相同的数字.

但是,你可以用compareTo()你想做的事情:

正如@assylias指出的那样,您还应该使用new BigDecimal("22.3")构造函数来避免双精度问题.

BigDecimal expected = BigDecimal.ZERO;
BigDecimal actual = new BigDecimal("22.3").multiply(BigDecimal.ZERO);
assertEquals(0, expected.compareTo(actual));
Run Code Online (Sandbox Code Playgroud)

还有一个名为的方法signum(),它返回-1,0或1表示负数,零和正数.所以你也可以测试零

assertEquals(0, actual.signum());
Run Code Online (Sandbox Code Playgroud)


ass*_*ias 47

您的代码有两个问题:

  • 你应该比较BigDecimal和compareTo而不是equals,正如其他答案所建议的那样
  • 但是你也应该使用字符串构造函数:new BigDecimal("22.3")而不是双构造函数new BigDecimal(22.3)来避免双精度问题

换句话说,以下代码(正确使用compareTo)仍然返回false:

BigDecimal bd = new BigDecimal(0.1).multiply(new BigDecimal(10));
System.out.println(bd.compareTo(BigDecimal.ONE) == 0);
Run Code Online (Sandbox Code Playgroud)

因为 0.1d * 10d != 1


Jig*_*shi 20

equals()BigDecimal检查的内部状态BigDecimal进行比较

请参阅以下代码

public boolean equals(Object x) {
    if (!(x instanceof BigDecimal))
        return false;
    BigDecimal xDec = (BigDecimal) x;
    if (x == this)
        return true;
    if (scale != xDec.scale)
        return false;
    long s = this.intCompact;
    long xs = xDec.intCompact;
    if (s != INFLATED) {
        if (xs == INFLATED)
            xs = compactValFor(xDec.intVal);
        return xs == s;
    } else if (xs != INFLATED)
        return xs == compactValFor(this.intVal);

    return this.inflate().equals(xDec.inflate());
}
Run Code Online (Sandbox Code Playgroud)

如果你想比较使用的值 compareTo()

将您的代码更改为

assertEquals(0 , new BigDecimal(0).compareTo(new BigDecimal(22.3).multiply(new BigDecimal(0)));
Run Code Online (Sandbox Code Playgroud)

更新:

使用构造函数将String作为BigDecimal的参数,以便精确检查下面的相关链接


另见