BigDecimal乘以零

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

基本的math告诉我乘以零的东西将等于零(参见: 零产品属性和乘法属性 )

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

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

这是一个BigDecimal不准确或有一些math的一个利基分支,我失踪的地方?

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

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

你可以使用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。 所以你也可以用零来testing

 assertEquals(0, actual.signum()); 

你的代码有两个问题:

  • 你应该比较BigDecimal与compareTo而不是等于,由其他答案build议
  • 但你也应该使用string构造函数: 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

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))); 

更新:

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


另见

  • 得到错误的结果评估100 * 2.55值
  • Java BigDecimal错误与String构造函数四舍五入ROUND_HALF_UP
Interesting Posts