30

我以前使用过 BigDecimals,但不是很频繁,今天早上我正在做一些事情,但我一直收到以下异常:

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion;
no exact representable decimal result.
    at java.math.BigDecimal.divide(BigDecimal.java:1594)

我试图设置比例并使用四舍五入来消除这样的问题:

    BigDecimal bd1 = new BigDecimal(1131).setScale(2,BigDecimal.ROUND_HALF_UP);
    BigDecimal bd2 = new BigDecimal(365).setScale(2,BigDecimal.ROUND_HALF_UP);
    BigDecimal bd3 = bd1.divide(bd2).setScale(2,BigDecimal.ROUND_HALF_UP);
    System.out.println("result: " + bd3);

但是,我不断收到同样的异常。谁能告诉我我在哪里犯了错误?

4

6 回答 6

65

非终止小数需要四舍五入

使用divide时应使用MathContextwithRoundingMode以防确切结果有无限位小数。

你的情况就是这样:

MathContext mc = new MathContext(2, RoundingMode.HALF_UP) ;
BigDecimal bd3 = bd1.divide(bd2, mc);

或者调用divide传递比例和舍入模式。

BigDecimal bd3 = bd1.divide(bd2, RoundingMode.HALF_UP);
于 2012-05-15T15:11:58.717 回答
4

这就是问题所在

bd1.divide(bd2)

您需要使用divide()采用舍入模式(以各种形式)的重载方法之一 - 您不能在除法之后进行舍入,因为对于非终止分数,中间结果要么已经需要舍入,要么需要无限的存储空间。

于 2012-05-15T15:11:53.180 回答
4

该问题是由会导致循环小数的操作(除法)引起的。

解决方法是在进行除法时指定一个比例,例如:

BigDecimal one = new BigDecimal("1");
BigDecimal three = new BigDecimal("3");
BigDecimal oneDivThree = one.divide(three, 200, RoundingMode.HALF_UP);
于 2012-05-15T15:17:14.740 回答
2

由于除法,您会收到此错误:

  1. 默认情况下,BigDecimal 总是尝试返回操作的确切结果。
  2. 因此,某些除法运算,如 1 除以 3,精确商将具有无限长的十进制扩展。这将导致除法操作失败并抛出上述错误。

在除法方法中提供比例和舍入模式(正如您在创建 BigDecimals 时所做的那样)以防止这种情况发生。

取自这里。还提供了工作划分的示例代码。

另请参阅:BigDecimal 上的 Java 文档

于 2012-05-15T15:11:14.880 回答
2

默认情况下,BigDecimal 尝试返回给定除法表达式的确切值。因此,如果由于无限小数扩展而无法确定确切的值,则会引发 ArithmeticException。一个基本的例子是用 1 除以 3,得到三分之一,这个值不能用十进制表示法精确表示。

于 2012-05-15T15:12:50.377 回答
0

要修复,您应该更改第三条语句,如下所示:

BigDecimal bd1 = new BigDecimal(1131).setScale(2,BigDecimal.ROUND_HALF_UP);
BigDecimal bd2 = new BigDecimal(365).setScale(2,BigDecimal.ROUND_HALF_UP);
BigDecimal bd3 = bd1.divide(bd2, 2, BigDecimal.ROUND_HALF_UP);
System.out.println("result: " + bd3);
于 2012-05-15T15:17:18.453 回答