BigDecimal除法为某些计算返回错误的结果

时间:2019-06-17 08:18:34

标签: java bigdecimal

我已经阅读了一些有关浮点数及其数学的问题。对我来说,问题似乎只在更大的范围内发生(即10+小数)。现在我的问题已经发生在2位小数,并且在某些情况下还存在很大问题:

以下代码:

System.out.println(
        String.format("%.2f", BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2).doubleValue()));
System.out.println(
        String.format("%.2f", BigDecimal.valueOf(2.41).divide(BigDecimal.valueOf(2.73), 2).doubleValue()));

分别生成此输出:

0.80
0.89

如果我手动执行计算(使用Google计算),则会得到以下结果:

0.72351421188
0.88278388278

对于第一个计算,结果确实很大(〜0.08 off),而对于第二个计算,结果非常低(〜0.01 off)。

关于第一个结果为何如此之大,是否有一些理智的解释?还是通过BigDecimal获得正确结果的任何方法?

请注意

System.out.println(2.8/3.87);

实际上返回正确的结果(0.7235142118863048)。

还请注意,String.format内容仅用于检查结果是否被更改(事实并非如此)。 BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2).doubleValue()产生完全相同的结果。

1 个答案:

答案 0 :(得分:6)

问题是您使用错误的BigDecimal#divide舍入到两位小数。以下是BigDecimal#divide方法的可用参数:

  • divide(BigDecimal divisor)
  • divide(BigDecimal divisor, int roundingMode)
  • divide(BigDecimal divisor, MathContext mc)
  • divide(BigDecimal divisor, RoundingMode roundingMode)
  • divide(BigDecimal divisor, int scale, int roundingMode)
  • divide(BigDecimal divisor, int scale, RoundingMode roundingMode)

由于您正在使用带有divideBigDecimal参数的int,因此它将使用divide(BigDecimal divisor, int roundingMode),其中2是舍入模式和比例。在这种情况下,2实际上是ROUND_CEILING,并且比例未指定。

相反,您必须使用divide(BigDecimal divisor, int scale, int roundingMode)divide(BigDecimal divisor, int scale, RoundingMode roundingMode)。因此,将您的通话更改为:

System.out.println(BigDecimal.valueOf(2.8).divide(BigDecimal.valueOf(3.87), 2, 
  BigDecimal.ROUND_HALF_UP));
System.out.println(BigDecimal.valueOf(2.41).divide(BigDecimal.valueOf(2.73), 2, 
  BigDecimal.ROUND_HALF_UP));

(随意使用ROUND_HALF_UP以外的舍入模式。)

Try it online.

我不确定默认情况下使用哪种比例,但是您用ROUND_CEILING指定的2导致了计算中的问题。


对于上述注释,可以使用三种方法来创建具有指定值的BigDecimal

  • BigDecimal.valueOf(2.8)
  • new BigDecimal(2.8)
  • new BigDecimal("2.8")

new BigDecimal(2.8)仍然会给出浮点错误,因此我建议您像以前一样使用BigDecimal.valueOf(2.8)或String构造函数new BigDecimal("2.8")

Try it online.

这与舍入问题无关,因为使用正确的divide方法将给出正确的结果,而与您使用的BigDecimal初始化无关:

Try it online.