BigDecimal java.lang.ArithmeticException: Rounding necessary

本文分析了BigDecimal在使用setScale方法时出现java.lang.ArithmeticException:Roundingnecessary异常的原因,并给出了正确的处理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在一次生产数据运算中

BigDecimal dbValue=new BigDecimal("200.2123333");

此时对数据进行字符串转化操作

dbValue.setScale(2).toString();出现java.lang.ArithmeticException: Rounding necessary异常,出现此问题的原因,具体没有分析出来,查看了jdk的源代码,第一个方法调用的是:133330_M8KW_946182.png

 

public BigDecimal setScale(int newScale, int roundingMode) {

        if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)

            throw new IllegalArgumentException("Invalid rounding mode");

 

        int oldScale = this.scale;

        if (newScale == oldScale)        // easy case

            return this;

        if (this.signum() == 0)            // zero can have any scale

            return BigDecimal.valueOf(0, newScale);

 

        long rs = this.intCompact;

        if (newScale > oldScale) {//在此处判断新的值是否比老的大,新的值默认为0

            int raise = checkScale((long)newScale - oldScale);

            BigInteger rb = null;

            if (rs == INFLATED ||

                (rs = longMultiplyPowerTen(rs, raise)) == INFLATED)

                rb = bigMultiplyPowerTen(raise);

            return new BigDecimal(rb, rs, newScale,

                                  (precision > 0) ? precision + raise : 0);

        } else {//走的else 调用divideAndRound

            // newScale < oldScale -- drop some digits

            // Can't predict the precision due to the effect of rounding.

            int drop = checkScale((long)oldScale - newScale);

            if (drop < LONG_TEN_POWERS_TABLE.length)

                return divideAndRound(rs, this.intVal,

                                      LONG_TEN_POWERS_TABLE[drop], null,

                                      newScale, roundingMode, newScale);

            else

                return divideAndRound(rs, this.intVal,

                                      INFLATED, bigTenToThe(drop),

                                      newScale, roundingMode, newScale);

        }

    }

private static BigDecimal divideAndRound(long ldividend, BigInteger bdividend,

                                             long ldivisor,  BigInteger bdivisor,

                                             int scale, int roundingMode,

                                             int preferredScale) {

        boolean isRemainderZero;       // record remainder is zero or not

        int qsign;                     // quotient sign

        long q = 0, r = 0;             // store quotient & remainder in long

        MutableBigInteger mq = null;   // store quotient

        MutableBigInteger mr = null;   // store remainder

        MutableBigInteger mdivisor = null;

        boolean isLongDivision = (ldividend != INFLATED && ldivisor != INFLATED);

        if (isLongDivision) {

            q = ldividend / ldivisor;

            if (roundingMode == ROUND_DOWN && scale == preferredScale)

                return new BigDecimal(null, q, scale, 0);

            r = ldividend % ldivisor;

            isRemainderZero = (r == 0);

            qsign = ((ldividend < 0) == (ldivisor < 0)) ? 1 : -1;

        } else {

            if (bdividend == null)

                bdividend = BigInteger.valueOf(ldividend);

            // Descend into mutables for faster remainder checks

            MutableBigInteger mdividend = new MutableBigInteger(bdividend.mag);

            mq = new MutableBigInteger();

            if (ldivisor != INFLATED) {

                r = mdividend.divide(ldivisor, mq);

                isRemainderZero = (r == 0);

                qsign = (ldivisor < 0) ? -bdividend.signum : bdividend.signum;

            } else {

                mdivisor = new MutableBigInteger(bdivisor.mag);

                mr = mdividend.divide(mdivisor, mq);

                isRemainderZero = mr.isZero();

                qsign = (bdividend.signum != bdivisor.signum) ? -1 : 1;

            }

        }

        boolean increment = false;

        if (!isRemainderZero) {

            int cmpFracHalf;

            /* Round as appropriate */

            if (roundingMode == ROUND_UNNECESSARY) {  // 在此出判断 如果==默认值 则抛出异常

                throw new ArithmeticException("Rounding necessary");

            } else if (roundingMode == ROUND_UP) {      // Away from zero

                increment = true;

            } else if (roundingMode == ROUND_DOWN) {    // Towards zero

                increment = false;

            } else if (roundingMode == ROUND_CEILING) { // Towards +infinity

                increment = (qsign > 0);

            } else if (roundingMode == ROUND_FLOOR) {   // Towards -infinity

                increment = (qsign < 0);

            } else {

                if (isLongDivision || ldivisor != INFLATED) {

                    if (r <= HALF_LONG_MIN_VALUE || r > HALF_LONG_MAX_VALUE) {

                        cmpFracHalf = 1;    // 2 * r can't fit into long

                    } else {

                        cmpFracHalf = longCompareMagnitude(2 * r, ldivisor);

                    }

                } else {

                    cmpFracHalf = mr.compareHalf(mdivisor);

                }

                if (cmpFracHalf < 0)

                    increment = false;     // We're closer to higher digit

                else if (cmpFracHalf > 0)  // We're closer to lower digit

                    increment = true;

                else if (roundingMode == ROUND_HALF_UP)

                    increment = true;

                else if (roundingMode == ROUND_HALF_DOWN)

                    increment = false;

                else  // roundingMode == ROUND_HALF_EVEN, true iff quotient is odd

                    increment = isLongDivision ? (q & 1L) != 0L : mq.isOdd();

            }

        }

        BigDecimal res;

        if (isLongDivision)

            res = new BigDecimal(null, (increment ? q + qsign : q), scale, 0);

        else {

            if (increment)

                mq.add(MutableBigInteger.ONE);

            res = mq.toBigDecimal(qsign, scale);

        }

        if (isRemainderZero && preferredScale != scale)

            res.stripZerosToMatchScale(preferredScale);

        return res;

    }


此时就想不通当初设计此方法的必要了

但是改变此写法就对了:

dbValue = dbValue.setScale(2, BigDecimal.ROUND_HALF_UP);

;再执行转化:dbValue.toString();

 

转载于:https://my.oschina.net/undermoonlightperson/blog/768329

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值