Non-terminating decimal expansion; no exact representable decimal result. 的恩恩怨怨

问题描述

在工作中,使用到BigDecimal类进行除法运算,结果系统在运行的过程中,发生了如下错误信息:

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.

at java.math.BigDecimal.divide(BigDecimal.java:1693)

翻译成中文的大体意思是没有终止的decimal 扩张,没有确切的可表达的deciaml结果。

翻译成人话就是除不尽。示例代码如下

BigDecimal divide = new BigDecimal(list.size).divide(new BigDecimal(slices));

说明list.size 除以slices 无法除尽。是不是这个原因呢?我们来做一个实验,看下面的代码:

BigDecimal divide = new BigDecimal(20).divide(new BigDecimal(3));

运行后,果然抛上面的错误。

将参数修改成

BigDecimal divide = new BigDecimal(20).divide(new BigDecimal(4));

运行后得到结果 5。说明就是这个问题,那么如何解决呢?

解决方式

既然是因为除不尽导致的,那么我们在除的时候指定进位方式:根据实际业务选择对应的进位方式

 BigDecimal divide = new BigDecimal(22).divide(new BigDecimal(4), RoundingMode.UP);

进位方式

1、RoundingMode.ROUND_UP:只要小数位不等于0,无条件向上取整(与向大取整不同)

官方给的例子如下:

  <table>

         <tr align=right><td>5.5</td>  <td>6</td>

         <tr align=right><td>2.5</td>  <td>3</td>

         <tr align=right><td>1.6</td>  <td>2</td>

         <tr align=right><td>1.1</td>  <td>2</td>

         <tr align=right><td>1.0</td>  <td>1</td>

         <tr align=right><td>-1.0</td> <td>-1</td>

         <tr align=right><td>-1.1</td> <td>-2</td>

         <tr align=right><td>-1.6</td> <td>-2</td>

         <tr align=right><td>-2.5</td> <td>-3</td>

         <tr align=right><td>-5.5</td> <td>-6</td>

   </table>

2、RoundingMode.ROUND_DOWN:与向上取整相反,向下取整

     <table>

         <tr align=right><td>5.5</td>  <td>5</td>

         <tr align=right><td>2.5</td>  <td>2</td>

         <tr align=right><td>1.6</td>  <td>1</td>

         <tr align=right><td>1.1</td>  <td>1</td>

         <tr align=right><td>1.0</td>  <td>1</td>

         <tr align=right><td>-1.0</td> <td>-1</td>

         <tr align=right><td>-1.1</td> <td>-1</td>

         <tr align=right><td>-1.6</td> <td>-1</td>

         <tr align=right><td>-2.5</td> <td>-2</td>

         <tr align=right><td>-5.5</td> <td>-5</td>

       </table>

3、RoundingMode.ROUND_CEILING:向大取整,意思是向大的方向取整

  <table>

         <tr align=right><td>5.5</td>  <td>6</td>

         <tr align=right><td>2.5</td>  <td>3</td>

         <tr align=right><td>1.6</td>  <td>2</td>

         <tr align=right><td>1.1</td>  <td>2</td>

         <tr align=right><td>1.0</td>  <td>1</td>

         <tr align=right><td>-1.0</td> <td>-1</td>

         <tr align=right><td>-1.1</td> <td>-1</td>

         <tr align=right><td>-1.6</td> <td>-1</td>

         <tr align=right><td>-2.5</td> <td>-2</td>

         <tr align=right><td>-5.5</td> <td>-5</td>

   </table>

4、RoundingMode.ROUND_FLOOR:向小的方向取整

     <table>

         <tr align=right><td>5.5</td>  <td>5</td>

         <tr align=right><td>2.5</td>  <td>2</td>

         <tr align=right><td>1.6</td>  <td>1</td>

         <tr align=right><td>1.1</td>  <td>1</td>

         <tr align=right><td>1.0</td>  <td>1</td>

         <tr align=right><td>-1.0</td> <td>-1</td>

         <tr align=right><td>-1.1</td> <td>-2</td>

         <tr align=right><td>-1.6</td> <td>-2</td>

         <tr align=right><td>-2.5</td> <td>-3</td>

         <tr align=right><td>-5.5</td> <td>-6</td>

     </table>

5、RoundingMode.ROUND_HALF_UP:半向相邻的方向取整,与哪个整数近,取哪个,0.5向上取整,如果是正数,0.5向大取整,如果是负数,0.5向小取整

<table> 

         <tr align=right><td>5.5</td>  <td>6</td>

         <tr align=right><td>2.5</td>  <td>3</td>

         <tr align=right><td>1.6</td>  <td>2</td>

         <tr align=right><td>1.1</td>  <td>1</td>

         <tr align=right><td>1.0</td>  <td>1</td>

         <tr align=right><td>-1.0</td> <td>-1</td>

         <tr align=right><td>-1.1</td> <td>-1</td>

         <tr align=right><td>-1.6</td> <td>-2</td>

         <tr align=right><td>-2.5</td> <td>-3</td>

         <tr align=right><td>-5.5</td> <td>-6</td>

 </table>

6、RoundingMode.ROUND_HALF_DOWN:半向相邻的方向取整,与哪个整数近,取哪个,0.5向下取整,如果是正数,0.5向小取整,如果是负数,0.5向大取整

<table>

         <tr align=right><td>5.5</td>  <td>5</td>

         <tr align=right><td>2.5</td>  <td>2</td>

         <tr align=right><td>1.6</td>  <td>2</td>

         <tr align=right><td>1.1</td>  <td>1</td>

         <tr align=right><td>1.0</td>  <td>1</td>

         <tr align=right><td>-1.0</td> <td>-1</td>

         <tr align=right><td>-1.1</td> <td>-1</td>

         <tr align=right><td>-1.6</td> <td>-2</td>

         <tr align=right><td>-2.5</td> <td>-2</td>

         <tr align=right><td>-5.5</td> <td>-5</td>

   </table>

7、RoundingMode.ROUND_HALF_EVEN:半偶数取整,主要针对半数0.5来说,向偶数取整

    <table>

          <tr align=right><td>5.5</td>  <td>6</td>

         <tr align=right><td>2.5</td>  <td>2</td>

         <tr align=right><td>1.6</td>  <td>2</td>

         <tr align=right><td>1.1</td>  <td>1</td>

         <tr align=right><td>1.0</td>  <td>1</td>

         <tr align=right><td>-1.0</td> <td>-1</td>

         <tr align=right><td>-1.1</td> <td>-1</td>

         <tr align=right><td>-1.6</td> <td>-2</td>

         <tr align=right><td>-2.5</td> <td>-2</td>

         <tr align=right><td>-5.5</td> <td>-6</td>

    </table>

8、RoundingMode.ROUND_UNNECESSARY:如果是小数则抛出异常

<table>

         <tr align=right><td>5.5</td>  <td>throw {@code ArithmeticException}</td>

         <tr align=right><td>2.5</td>  <td>throw {@code ArithmeticException}</td>

         <tr align=right><td>1.6</td>  <td>throw {@code ArithmeticException}</td>

         <tr align=right><td>1.1</td>  <td>throw {@code ArithmeticException}</td>

         <tr align=right><td>1.0</td>  <td>1</td>

         <tr align=right><td>-1.0</td> <td>-1</td>

         <tr align=right><td>-1.1</td> <td>throw {@code ArithmeticException}</td>

         <tr align=right><td>-1.6</td> <td>throw {@code ArithmeticException}</td>

         <tr align=right><td>-2.5</td> <td>throw {@code ArithmeticException}</td>

         <tr align=right><td>-5.5</td> <td>throw {@code ArithmeticException}</td>

   </table>

在代码中找到commonNeedIncrement方法,用来 判断是否需要进位

private static boolean commonNeedIncrement(int roundingMode, int qsign,
                                        int cmpFracHalf, boolean oddQuot) {
        switch(roundingMode) {
        case ROUND_UNNECESSARY:
            throw new ArithmeticException("Rounding necessary");

        case ROUND_UP: // Away from zero
            return true;

        case ROUND_DOWN: // Towards zero
            return false;

        case ROUND_CEILING: // Towards +infinity
            return qsign > 0;

        case ROUND_FLOOR: // Towards -infinity
            return qsign < 0;

        default: // Some kind of half-way rounding
            assert roundingMode >= ROUND_HALF_UP &&
                roundingMode <= ROUND_HALF_EVEN: "Unexpected rounding mode" + RoundingMode.valueOf(roundingMode);

            if (cmpFracHalf < 0 ) // We're closer to higher digit
                return false;
            else if (cmpFracHalf > 0 ) // We're closer to lower digit
                return true;
            else { // half-way
                assert cmpFracHalf == 0;

                switch(roundingMode) {
                case ROUND_HALF_DOWN:
                    return false;

                case ROUND_HALF_UP:
                    return true;

                case ROUND_HALF_EVEN:
                    return oddQuot;

                default:
                    throw new AssertionError("Unexpected rounding mode" + roundingMode);
                }
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/zanpengfei/article/details/124043806
今日推荐