【问题标题】:What causes "Non-terminating decimal expansion" exception from BigDecimal.divide? [duplicate]是什么导致 BigDecimal.divide 出现“非终止十进制扩展”异常? [复制]
【发布时间】:2012-05-15 15:07:14
【问题描述】:

我以前使用过 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);

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

【问题讨论】:

标签: java exception bigdecimal


【解决方案1】:

非终止小数需要四舍五入

使用divide 时,您应该使用MathContextRoundingMode,以防确切的结果有无限位小数。

这就是你的情况:

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

或者使用舍入模式调用divide 以使用分子的刻度(在下面的示例中为bd1):

BigDecimal bd3 = bd1.divide(bd2, RoundingMode.HALF_UP);

【讨论】:

  • 感谢您解决了问题。我也尝试过使用 MathContext,但看起来我做错了。
  • 我喜欢你展示两种方式的事实。起初我想,为什么有人会使用MathContext。然后我恍然大悟。呃……为了一致性……
  • 我做new BigDecimal(350000.00).divide(new BigDecimal(1)) 并且我仍然得到“非终止十进制扩展;没有精确可表示的十进制结果”异常。我不明白为什么结果不是简单的 350000,请您详细说明一下吗?
  • @Michael 使用了 bd1 的比例(通过单击链接查看 javadoc)。我会澄清的。
  • @assylias 感谢您提供信息。 JavaDoc 实际上提到了这一点,但是当我第一次阅读它时,它并没有立即跳出我的意思,现在它是有道理的:“谁的值是(this / divisor),谁的首选比例是(this.scale () - 除数.scale());"
【解决方案2】:

问题来了

bd1.divide(bd2)

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

【讨论】:

    【解决方案3】:

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

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

    BigDecimal one = new BigDecimal("1");
    BigDecimal three = new BigDecimal("3");
    BigDecimal oneDivThree = one.divide(three, 200, RoundingMode.HALF_UP);
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

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

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

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

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

        另请参阅:Java docs on BigDecimal

        【讨论】:

        • 好像不是你说的,所以我google了一下,找到了这个。 jaydeepm.wordpress.com/2009/06/04/… 哈哈。
        • @Vulcan 他们不是,但我总是链接到来源。只需首先完成答案即可。最好的答案是引号。
        • 解决问题的不是比例尺,而不是 RoundingMode?​​span>
        • @NeilCoffey 是的,没错。我会编辑。
        • @Vulcan 在提供资源时,我认为应该鼓励。
        【解决方案6】:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-05-19
          • 2016-10-21
          • 2018-07-28
          • 1970-01-01
          • 2014-09-18
          • 1970-01-01
          相关资源
          最近更新 更多