Java 大十进制乘零
我正在用BigDecimal执行一个简单的乘法,并且我发现了一些奇怪的行为(在这个用例中,乘零是正确的) 基础数学告诉我,任何乘以零的东西都等于零(见:和) 但是,以下代码将始终失败,并出现相同的错误: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不能像此断
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)
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
@MartinLarssonBigDecimal
的要点是它不会受到近似或截断错误的影响(对于非循环小数)。如答案中所述,该问题是由于误用接口造成的。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);