文档章节

BigDecimal java.lang.ArithmeticException: Rounding necessary

我的最爱是那个人
 我的最爱是那个人
发布于 2016/10/22 12:33
字数 579
阅读 689
收藏 0

在一次生产数据运算中

BigDecimal dbValue=new BigDecimal("200.2123333");

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

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

 

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

 

© 著作权归作者所有

下一篇: mac brew 问题
我的最爱是那个人
粉丝 4
博文 45
码字总数 39769
作品 0
朝阳
程序员
私信 提问
Bigdecimal类型使用 保留小数位

bigdecimal 保留小数位 实际开发中,会出现数值为空的情况,这时类的getter和setter方法应该判断是否传入为空或者直接在Bigdecimal 类型属性上初始化,如: private BigDecimal income = new ...

要么伟大要么死_zcv
2016/12/16
10
0
【java】使用BigDecimal计算时候注意事项

一般数据在用BigDecimal自带的运算方式时候是不会出现问题的,但是碰到了无限小数的时候,这个类直接运算方式就会出现一些取不到位或者溢出的错误。 错误1:Non-terminating decimal expansi...

tr1912
2018/03/31
0
0
Rounding necessary 异常问题解决

1.异常图片 public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {} 意思是说:我用一个BigDecimal对象除以divisor后的结果,并且要求这个结果保留有scale个小数位,...

沉淀人生
2018/08/09
0
0
java.math.BigDecimal保留两位小数,保留小数,精确位数

java保留两位小数问题: 方式一(四舍五入形式保留两位小数,注意模式ROUNDHALFUP): 四舍五入 double f = 111231.5585; BigDecimal b = new BigDecimal(f); double f1 = b.setScale(2, BigD...

vshcxl
2016/10/27
2.2K
0
BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,异常处理

BigDecimal的divide方法进行除法时当不整除,出现无限循环小数时,就会抛异常的,异常 如下:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable ...

郏高阳
2014/05/27
0
0

没有更多内容

加载失败,请刷新页面

加载更多

【AI实战】手把手教你深度学习文字识别(文字检测篇:基于MSER, CTPN, SegLink, EAST等方法)

文字检测是文字识别过程中的一个非常重要的环节,文字检测的主要目标是将图片中的文字区域位置检测出来,以便于进行后面的文字识别,只有找到了文本所在区域,才能对其内容进行识别。 文字检...

雪饼
今天
15
0
思维导图XMind 8 Pro 绿化方法(附序列号)

按部就班: Step 1 -全新下载最新版本的 Xmind 8(注必须是英文官方的版本,中文代{过}{滤}理网站的版本修改过,无法使用pj); Step 2 -安装完毕后,点击文末的下载按钮下载pj补丁文件包,将...

一只小青蛙
今天
10
0
数据结构(ER数据库)设计规范

表命名规范 表命名的规则分为3个层级,层级之间通过_分割,例如b_r_identity、d_l_identity。规约为: [leavel]_[type]_[name] [leavel] 表示数据库表的层级和功能,分为: s:业务无关的系统...

随风溜达的向日葵
今天
10
0
阿里Sentinel控制台源码修改-对接Apollo规则持久化

https://github.com/alibaba/Sentinel/wiki/%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Sentinel 动态规则扩展 https://github.com/alibaba/Sentinel/wiki......

jxlgzwh
昨天
14
0
在Linux系统中创建SSH服务器别名

如果你经常通过 SSH 访问许多不同的远程系统,这个技巧将为你节省一些时间。你可以通过 SSH 为频繁访问的系统创建 SSH 别名,这样你就不必记住所有不同的用户名、主机名、SSH 端口号和 IP 地...

老孟的Linux私房菜
昨天
13
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部