Java 大十进制乘零

Java 大十进制乘零,java,bigdecimal,numerical-analysis,rounding-error,Java,Bigdecimal,Numerical Analysis,Rounding Error,我正在用BigDecimal执行一个简单的乘法,并且我发现了一些奇怪的行为(在这个用例中,乘零是正确的) 基础数学告诉我,任何乘以零的东西都等于零(见:和) 但是,以下代码将始终失败,并出现相同的错误: assertEquals(new BigDecimal(0), new BigDecimal(22.3).multiply(new BigDecimal(0))); 这是BigDecimal的错误,还是我遗漏了数学的某个小分支 注意:运行在Intellij11中的JDK1.6.027不能像此断

我正在用BigDecimal执行一个简单的乘法,并且我发现了一些奇怪的行为(在这个用例中,乘零是正确的)

基础数学告诉我,任何乘以零的东西都等于零(见:和)

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

assertEquals(new BigDecimal(0), new BigDecimal(22.3).multiply(new BigDecimal(0)));
这是BigDecimal的错误,还是我遗漏了数学的某个小分支


注意:运行在Intellij11中的JDK1.6.027不能像此断言那样使用
equals()
方法来比较
BigDecimals
。这是因为此equals函数将比较刻度。如果刻度不同,
equals()
将返回false,即使它们在数学上是相同的数字

但是,您可以使用
compareTo()
执行您想要的操作:

正如@assylias指出的,您还应该使用
新的BigDecimal(“22.3”)
构造函数来避免双精度问题

BigDecimal expected = BigDecimal.ZERO;
BigDecimal actual = new BigDecimal("22.3").multiply(BigDecimal.ZERO);
assertEquals(0, expected.compareTo(actual));
还有一个方法叫做
signum()
,它返回-1、0或1表示负、零和正。因此,您也可以使用

assertEquals(0, actual.signum());
equals()
on检查
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());
}
如果要比较这些值,请使用

将代码更改为

assertEquals(0 , new BigDecimal(0).compareTo(new BigDecimal(22.3).multiply(new BigDecimal(0)));

更新:

使用构造函数将字符串作为BigDecimal的参数,以确保精度的准确性。请检查下面的相关链接


另请参见


您的代码有两个问题:

  • 正如其他答案所建议的,您应该将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);

因为
0.1d*10d!=1

是的,研究数值分析,尤其是近似和截断误差,或者在
双精度
中,您可以编写
assertEquals(0,23.3*0,0);)还可以查看
BigDecimal.ZERO
@MartinLarsson
BigDecimal
的要点是它不会受到近似或截断错误的影响(对于非循环小数)。如答案中所述,该问题是由于误用接口造成的。BigDecimal是Java中的一个经典示例,其中compareTo的约定与equals不一致,您似乎遇到过这种情况。@assylias”,但您还应该使用字符串构造函数:new BigDecimal(“22.3”)而不是双构造函数new BigDecimal(22.3)避免双精度问题。你能解释一下双精度问题吗?@Geek试试这个
System.out.println(新的BigDecimal(“0.1”);
和这个
System.out.println(新的BigDecimal(0.1d));
。第一个(字符串构造函数)打印
0.1
,而第二个(双构造函数)打印
0.100000000000000551151231257827021181583404540105625
。发生这种情况是因为双精度不能精确表示0.1。有关它的详细信息。@assylias+1以获得澄清。
BigDecimal bd = new BigDecimal(0.1).multiply(new BigDecimal(10));
System.out.println(bd.compareTo(BigDecimal.ONE) == 0);