ArithmeticException:“不结束的十进制扩展;没有确切可表示的小数结果”


507

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

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.

Answers:


841

Java 11 BigDecimal文档

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

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

如果商具有不间断的十进制扩展数,并且指定了该操作以返回精确的结果,ArithmeticException则会引发an 。否则,将返回除法的精确结果,就像其他操作一样。

要解决此问题,您需要执行以下操作

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

其中2是小数位数,RoundingMode.HALF_UP是四舍五入模式

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


3
这个作品碧玉错误太感谢community.jaspersoft.com/questions/528968/...
谢里夫

27
2不是precision; 是scale。请参阅docs.oracle.com/javase/7/docs/api/java/math/…–
John

(new BigDecimal(100))。divide(new BigDecimal(0.90),2,RoundingMode.HALF_UP)
egemen

@AnandVarkeyPhilips这是规模。参见Javadoc。编辑被拒绝。
罗恩侯爵

@ user207421,我无意中编辑它,并试图恢复..但没有足够的点数,以删除编辑.... meta.stackexchange.com/questions/80933/...
阿南德VARKEY飞利浦

76

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

但是,如果您提供RoundingMode和精度,则它将能够将(例如1.333333333-to-infinity)转换为类似1.3333的值……但是作为程序员,您需要告诉它您对“精度”感到满意'。



13

为了解决这个问题,我使用了以下代码

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

2是精度。现在问题已解决。


3
除代码外,还应提供一些解释。
马丁·塞拉诺

11
2不是precision; 是scale。请参阅docs.oracle.com/javase/7/docs/api/java/math/…–
John

3
对于金融应用程序,建议使用RoundingMode.HALF_EVEN。这就是银行业所使用的
ACV

针对这一情况,谁是精密约翰Mankos的评论感到困惑,请参阅这个答案stackoverflow.com/questions/4591206/...
斯廷普森猫

5

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

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

我改为之前阅读的答案,因为我没有写十进制精度:

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

4是十进制精度

AND RoundingMode是Enum常数,您可以选择任何一个 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/


4是规模,而不是精度。
罗恩侯爵


1

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

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


0

您的程序不知道使用十进制数字的精度,因此它抛出:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.