571

为什么以下代码会引发如下所示的异常?

BigDecimal a = new BigDecimal("1.6");
BigDecimal b = new BigDecimal("9.2");
a.divide(b) // results in the following exception.

例外:

java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
4

9 回答 9

955

来自Java 11BigDecimal文档

MathContext对象的精度设置为 0(例如)时,算术运算是精确的,就像不带对象MathContext.UNLIMITED的算术方法一样。MathContext(这是 5 之前的版本中唯一支持的行为。)

作为计算精确结果的必然结果,MathContext不使用精度设置为 0 的对象的舍入模式设置,因此不相关。在除法的情况下,精确商可以有一个无限长的小数展开;例如,1 除以 3。

如果商具有非终止的十进制扩展并且指定操作返回精确结果,ArithmeticException则抛出 an。否则,将返回除法的确切结果,就像其他操作一样。

要修复,您需要执行以下操作

a.divide(b, 2, RoundingMode.HALF_UP)

其中 2 是比例,RoundingMode.HALF_UP 是舍入模式

有关更多详细信息,请参阅此博客文章

于 2011-01-04T06:37:35.633 回答
83

因为您没有指定精度和舍入模式。BigDecimal 抱怨它可以使用 10、20、5000 或无穷小数位,但它仍然无法为您提供数字的精确表示。因此,它不会给你一个不正确的 BigDecimal,而是对你发牢骚。

但是,如果您提供 RoundingMode 和精度,那么它将能够转换(例如 1.333333333-to-infinity 到 1.3333 之类的东西......但是作为程序员,您需要告诉它您对什么精度感到满意'。

于 2011-01-04T06:39:55.833 回答
70

你可以做

a.divide(b, MathContext.DECIMAL128)

您可以选择所需的位数:32、64 或 128。

看看这个链接:

http://edelstein.pebbles.cs.cmu.edu/jadeite/main.php?api=java6&state=class&package=java.math&class=MathContext

于 2013-03-06T02:49:26.870 回答
17

为了解决这样的问题,我使用了下面的代码

a.divide(b, 2, RoundingMode.HALF_EVEN)

二是精准。现在问题解决了。

于 2015-03-26T18:23:40.303 回答
7

我遇到了同样的问题,因为我的代码行是:

txtTotalInvoice.setText(var1.divide(var2).doubleValue() + "");

我改成这个,阅读以前的答案,因为我没有写小数精度:

txtTotalInvoice.setText(var1.divide(var2,4, RoundingMode.HALF_UP).doubleValue() + "");

4 是小数精度

AND RoundingMode 是枚举常量,您可以选择其中的任何一个 UP, DOWN, CEILING, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP

在这种情况下 HALF_UP,将有以下结果:

2.4 = 2   
2.5 = 3   
2.7 = 3

您可以在RoundingMode此处查看信息:http ://www.javabeat.net/precise-rounding-of-decimals-using-rounding-mode-enumeration/

于 2014-11-15T20:38:29.320 回答
4

这是一个四舍五入的问题,我的解决方案如下。

divider.divide(dividend,RoundingMode.HALF_UP);
于 2018-08-07T13:32:02.137 回答
3

BigDecimal的答案抛出 ArithmeticException

public static void main(String[] args) {
        int age = 30;
        BigDecimal retireMentFund = new BigDecimal("10000.00");
        retireMentFund.setScale(2,BigDecimal.ROUND_HALF_UP);
        BigDecimal yearsInRetirement = new BigDecimal("20.00");
        String name = " Dennis";
        for ( int i = age; i <=65; i++){
            recalculate(retireMentFund,new BigDecimal("0.10"));
        }
        BigDecimal monthlyPension =   retireMentFund.divide(
                yearsInRetirement.divide(new BigDecimal("12"), new MathContext(2, RoundingMode.CEILING)), new MathContext(2, RoundingMode.CEILING));      
        System.out.println(name+ " will have £" + monthlyPension +" per month for retirement");
    }
public static void recalculate (BigDecimal fundAmount, BigDecimal rate){
        fundAmount.multiply(rate.add(new BigDecimal("1.00")));
    }

在您的 divide 方法调用中添加 MathContext 对象并调整精度和舍入模式。这应该可以解决您的问题

于 2016-06-20T16:53:22.923 回答
2

你的程序不知道十进制数使用什么精度,所以它抛出:

java.lang.ArithmeticException: Non-terminating decimal expansion

绕过异常的解决方案:

MathContext precision = new MathContext(int setPrecisionYouWant); // example 2
BigDecimal a = new BigDecimal("1.6",precision);
BigDecimal b = new BigDecimal("9.2",precision);
a.divide(b) // result = 0.17
于 2018-06-29T09:48:35.377 回答
1

对我来说,它正在处理这个问题:

BigDecimal a = new BigDecimal("9999999999.6666",precision);
BigDecimal b = new BigDecimal("21",precision);

a.divideToIntegralValue(b).setScale(2)
于 2021-02-05T01:14:08.047 回答