我正在使用BigDecimal进行简单的乘法运算,在乘以零时我发现了一些奇怪的行为(在这个用例中乘以零是正确的)。
基础数学告诉我,任何乘以零的数字都将等于零(参见:Zero Product Property和Multiplication Properties)
但是,以下代码将始终失败并出现相同的错误:
assertEquals(new BigDecimal(0), new BigDecimal(22.3).multiply(new BigDecimal(0)));
java.lang.AssertionError: Expected :0 Actual :0E-48
这对BigDecimal来说是不准确的还是我在某处遗漏了数学的一些利基分支?
注意:在IntelliJ 11中运行的JDK 1.6.0_27
答案 0 :(得分: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));
还有一个名为signum()
的方法,它为负数,零和正数返回-1,0或1。所以你也可以用
assertEquals(0, actual.signum());
答案 1 :(得分:47)
您的代码有两个问题:
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
答案 2 :(得分:20)
BigDecimal
上的 equals()
检查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());
}
如果要比较值,请使用compareTo()
将您的代码更改为
assertEquals(0 , new BigDecimal(0).compareTo(new BigDecimal(22.3).multiply(new BigDecimal(0)));
更新:
使用构造函数将String作为BigDecimal的参数,以便精确检查下面的相关链接
另见