首页 > 解决方案 > 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

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

0.72351421188
0.88278388278

对于第一次计算,结果非常大(约 0.08 折),而对于第二次计算,结果非常低(约 0.01 折)。

关于为什么第一个结果如此之大,是否有一些理智的解释?或任何方法来获得正确的结果使用BigDecimal

注意

System.out.println(2.8/3.87);

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

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

标签: javabigdecimal

解决方案


问题是您使用了错误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)

由于您使用divide带有 aBigDecimalint参数的 a,因此它使用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。)

在线尝试。

我不确定默认情况下它使用什么比例,但是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")

在线尝试。

然而,这与您的舍入问题有点无关,因为无论您使用了何种初始化,使用正确的divide方法都会给出正确的结果:BigDecimal

在线尝试。


推荐阅读