Search code examples
javabigdecimal

Dividing BigDecimals


Trying to deal with BigDecimals. Receiving an arithmetical exception when trying to divide BigDecimals, say 10 by 3 (result is a period value).

If I use rounding with specifyed number of digits: in case of say 10 / 3 I will receive right result 3.3333333, but in case of 10 / 8 I am receiving 1.25000000. I want to receive 3.33333333 in first case and 1.25.

Is there a universal solution?

My code is:

BigDecimal b1 = new BigDecimal("10");
BigDecimal b2 = new BigDecimal("3");

try {
    // updated
    BigDecimal b3 = b1.divide(b2, 8, RoundingMode.HALF_UP);
    System.out.println(b3.toString());
} catch (ArithmeticException e) {
    System.out.println("Oops");
}

Solution

  • You need a RoundingMode for example:

    BigDecimal b3 = b1.divide(b2, 2, RoundingMode.HALF_UP);
    

    All explained here: Stack Overflow - ArithmeticException: “Non-terminating decimal expansion; no exact representable decimal result”.

    Using your solution b3 = b1.divide(b2, 8, RoundingMode.HALF_UP); (8 digits). It works fine in case of say 10 / 3, but in case of 10 / 8 I receive result 1.25000000. I want to receive 3.88888888 in first case and 1.25 in second. How to do this?

    You need an extra static helper method, my complete solution:

    import java.math.BigDecimal;
    import java.math.RoundingMode;
    
    public class BigDecimalDivider {
    
        public static BigDecimal divideAutoScale(BigDecimal val1, BigDecimal val2,
                int scale, RoundingMode roundingMode) {
            BigDecimal result = val1.divide(val2, scale, roundingMode);
            return result.setScale(countScale(result));
        }
    
        /*
         * Static helper method, returns int scale.
         */
    
        private static int countScale(BigDecimal bd) {
    
            if (bd.doubleValue() % 2 == 0) {
                return 0;
            } else {
    
                String bigDec = bd.toString();
                int counter = 0;
    
                for (int i = bigDec.length() - 1; i >= 0; i--) {
    
                    if (bigDec.charAt(bigDec.length() - 1) != '0') {
                        break;
                    }
    
                    if (bigDec.charAt(i) == '0') {
                        counter++;
                    }
    
                    if (bigDec.charAt(i) == '.'
                            || (i > 1 && bigDec.charAt(i) == '0' && bigDec
                                    .charAt(i - 1) != '0')) {
                        break;
                    }
                }
    
                return bigDec.substring(bigDec.indexOf('.'), bigDec.length() - 1)
                        .length() - counter;
            }
        }
    
        /*
         * Example of usage
         */
    
        public static void main(String[] args) {
            BigDecimal b1 = new BigDecimal("10");
            BigDecimal b2 = new BigDecimal("5");
    
            BigDecimal result = divideAutoScale(b1, b2, 4, RoundingMode.HALF_UP);
            System.out.println(result);
        }
        }
    

    Result: 5

    Other tests:

    10 / 3 : 3.3333

    10 / 8 : 1.25