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

使用BigDecimal进行出发运算(调用divide())时出现的,是因为不整除产生无先循环小数所致。源码如下:

 public BigDecimal divide(BigDecimal divisor) {
        BigInteger p = this.getUnscaledValue();
        BigInteger q = divisor.getUnscaledValue();
        BigInteger gcd; // greatest common divisor between 'p' and 'q'
        BigInteger quotAndRem[];
        long diffScale = (long)scale - divisor.scale;
        int newScale; // the new scale for final quotient
        int k; // number of factors "2" in 'q'
        int l = 0; // number of factors "5" in 'q'
        int i = 1;
        int lastPow = FIVE_POW.length - 1;

        if (divisor.isZero()) {
            throw new ArithmeticException("Division by zero");
        }
        if (p.signum() == 0) {
            return zeroScaledBy(diffScale);
        }
        // To divide both by the GCD
        gcd = p.gcd(q);
        p = p.divide(gcd);
        q = q.divide(gcd);
        // To simplify all "2" factors of q, dividing by 2^k
        k = q.getLowestSetBit();
        q = q.shiftRight(k);
        // To simplify all "5" factors of q, dividing by 5^l
        do {
            quotAndRem = q.divideAndRemainder(FIVE_POW[i]);
            if (quotAndRem[1].signum() == 0) {
                l += i;
                if (i < lastPow) {
                    i++;
                }
                q = quotAndRem[0];
            } else {
                if (i == 1) {
                    break;
                }
                i = 1;
            }
        } while (true);
        // If  abs(q) != 1  then the quotient is periodic
        if (!q.abs().equals(BigInteger.ONE)) {
        //异常信息
            throw new ArithmeticException("Non-terminating decimal expansion; no exact representable decimal result");
        }
        // The sign of the is fixed and the quotient will be saved in 'p'
        if (q.signum() < 0) {
            p = p.negate();
        }
        // Checking if the new scale is out of range
        newScale = safeLongToInt(diffScale + Math.max(k, l));
        // k >= 0  and  l >= 0  implies that  k - l  is in the 32-bit range
        i = k - l;

        p = (i > 0) ? Multiplication.multiplyByFivePow(p, i)
        : p.shiftLeft(-i);
        return new BigDecimal(p, newScale);
    }

解决方案:

使用三参数除法函数divide(),指定小数精确度。如:

new BigDecimal(mGypsumCountSum).divide(new BigDecimal(count),8,BigDecimal.ROUND_HALF_UP)

此处divide()的第二个参数是8表示小数精确8位。

<think>好的,我现在要解决用户在Java中遇到的`java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result`异常问题。这个问题通常出现在使用`BigDecimal`进行除法运算时,当结果是一个无限不循环小数,而没有指定舍入模式的情况下。我需要仔细分析原因,并提供有效的解决方案。 首先,用户的问题是关于非终止小数扩展导致的异常。我应该回忆一下`BigDecimal`的除法运算方法。记得`BigDecimal.divide()`方法有多个重载版本,其中必须指定舍入模式(RoundingMode)的情况,尤其是在结果无法精确表示时。如果用户没有提供舍入模式,就会抛出这个异常。比如,当进行1除以3这样的运算,结果无限循环,无法精确表示,这时候如果不指定如何舍入,就会出错。 接下来,我需要考虑如何正确使用`divide()`方法。正确的做法是在调用方法时,除了传入除数,还要指定舍入模式和精度。例如,使用`RoundingMode.HALF_UP`这样的常见舍入方式。另外,可能还需要设置结果的精度,比如使用另一个重载方法,同时指定小数位数和舍入模式。 然后,我需要给出具体的代码示例,说明如何避免这个异常。比如,展示正确使用`divide()`方法的代码,以及如何处理不同的情况,如已知结果可能是无限小数的情况,或者需要精确控制小数位数的情况。 此外,可能还需要提醒用户注意其他可能引发类似异常的场景,比如在使用`divideAndRemainder()`方法时,如果没有正确设置舍入模式,也可能导致问题。不过,用户当前的问题主要集中在`divide()`方法上,所以重点应放在这里。 最后,总结解决方案,强调必须指定舍入模式,并提供不同的应用场景示例,确保用户能够根据实际需求选择合适的处理方式。同时,可能需要解释为什么这个异常会发生,帮助用户理解背后的原理,从而更好地避免类似问题。</think>在Java中,`java.lang.ArithmeticException: Non-terminating decimal expansion`异常通常发生在使用`BigDecimal`进行除法运算时,结果无法精确表示为有限小数且未指定舍入模式。以下是逐步解决方案: --- ### 1. 问题原因分析 当使用`BigDecimal.divide()`进行除法运算时,若结果是无尽小数(如$1/3 = 0.\overline{3}$),且未定义舍入规则,Java会抛出此异常[^1]。 --- ### 2. 核心解决方法 使用`divide()`方法时**必须指定舍入模式**(`RoundingMode`)和精度: ```java BigDecimal a = new BigDecimal("1"); BigDecimal b = new BigDecimal("3"); BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP); // 保留2位小数,四舍五入 ``` --- ### 3. 不同场景的解决方案 #### 场景1:已知结果为无限小数 ```java // 明确设置小数位数和舍入模式 BigDecimal result = a.divide(b, 4, RoundingMode.HALF_EVEN); ``` #### 场景2:需要完全精确计算 ```java // 使用MathContext定义总精度 MathContext mc = new MathContext(10, RoundingMode.CEILING); BigDecimal result = a.divide(b, mc); ``` #### 场景3:整数除法要求余数 ```java BigDecimal[] results = a.divideAndRemainder(b); System.out.println("商:" + results[0] + " 余数:" + results[1]); ``` --- ### 4. 关键注意事项 - `RoundingMode`包含多种模式:`HALF_UP`(四舍五入)、`CEILING`(向正无穷舍入)、`FLOOR`(向负无穷舍入)等 - 精度设置需结合业务需求,如金融计算常用`HALF_EVEN`(银行家舍入法) --- ### 代码示例 ```java public static void safeDivision() { try { BigDecimal numerator = new BigDecimal("10"); BigDecimal denominator = new BigDecimal("3"); BigDecimal result = numerator.divide(denominator, 5, RoundingMode.HALF_UP); System.out.println("安全计算结果:" + result); // 输出3.33333 } catch (ArithmeticException e) { System.out.println("异常已正确处理"); } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值