BigDecimal乘法

5

我尝试使用multiply方法将两个BigDecimal值相乘,代码如下:

BigDecimal dur = BigDecimal.valueOf(60/1.1);
BigDecimal bal = BigDecimal.valueOf(1.1);

BigDecimal ans  = dur.multiply(bal);

System.out.println("Ans:"+ans);

我期望的答案是60,但实际得到的是:

Ans:59.999999999999994

为什么会出现这个问题,我们该如何解决?

5
60/1.1没有有限的小数表示形式,因此不能被精确地表示为BigDecimal。 - Jon Skeet
1
有趣的是,使用“double”的结果是“60.0”... - Boris the Spider
1
@BoristheSpider,一个更简单的例子是 1.0 / 3 * 3,当使用 double 时结果为 1.0,但使用 BigDecimal 时需要额外进行舍入。 - Peter Lawrey
2个回答

5
您需要使用String构造函数,而不是double构造函数。60/1.1没有String表示形式,因为它是54.(54)BigDecimal不支持无法写成固定长度小数的数字。
BigDecimal Javadoc中可以看到:
引用:

在除法的情况下,精确商可能具有无限长的小数扩展;例如,1除以3。如果商有一个非终止的小数扩展,并且规定该操作返回一个精确结果,则会抛出ArithmeticException。否则,将返回除法的精确结果,就像其他操作一样。


2
虽然通常情况下这可能是答案,但在这种情况下并不能帮助你,因为虽然“1.1”对于第二个 BigDecimal 来说是一个很好的字符串,但你会用什么来表示第一个呢? - Jon Skeet
请看我的修改:我已经添加了信息,60/1.1 不能用 BigDecimal 表示。 - Michal Kordas

5
问题在于你有一个无法用 double 表示的值,但也不能用 BigDecimal 表示,因此必须进行合理的四舍五入以获得预期的解决方案。
double d = 60 / 1.1 * 1.1;
System.out.println("double without rounding: " + d);
System.out.printf("double With rounding %.2f%n", d);

BigDecimal bd = BigDecimal.valueOf(60).divide(BigDecimal.valueOf(1.1), 9, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(1.1));
System.out.println("BigDecimal without rounding: " + bd);
System.out.printf("BigDecimal with rounding %.2f%n", bd);
// or
bd = bd.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("BigDecimal with rounding: " + bd);

打印

double without rounding: 60.0
double With rounding 60.00
BigDecimal without rounding: 59.9999999995
BigDecimal with rounding 60.00
BigDecimal with rounding: 60.00

注意:对于这些值,double 恰好能正确地舍入并给出正确的答案。但是,如果选择不同的组合,则会得到错误的结果。例如:54.545454545454545 * 1.1 => 60.00000000000001

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接