-1

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");
}
  • 1
    Down-vote from me - no evidence of prior research before posting this question. – Duncan Jones Mar 23 '15 at 12:17
  • 1
    And just to be precise here: ROUNDING is one way to resolve the problem at hand; but it is not the only option. It really depends on the requirements of your program. There might be situations, where rounding is wrong; and instead the error needs to be propagated. – GhostCat Mar 23 '15 at 12:17

1 Answers1

1

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

Community
  • 1
  • 1
RichardK
  • 3,228
  • 5
  • 32
  • 52
  • Rounding is just ONE option. I wouldn't say that this the general "answer". What if the requirements to the underlying application are actually to NOT round? – GhostCat Mar 23 '15 at 12:15
  • If "*all explained here*", then **here** is a duplicate. Don't post an answer, flag this question as duplicate instead. (Thanks for finding that, by the way). – Duncan Jones Mar 23 '15 at 12:15
  • I have answered, because it was harder to find such answer, this topic is more revelant in some case. It will help to find this question in future. – RichardK Mar 23 '15 at 12:17
  • @RichardK No, that's the wrong thing to do. This question will remain in existence and will act as a sign-post to the duplicate. It doesn't need answers in it to serve that goal. – Duncan Jones Mar 23 '15 at 12:17
  • Ok, sorry. I will keep that in mind. – RichardK Mar 23 '15 at 12:18
  • Thank you. This is for calculator app and rounding is ok. 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? –  Mar 23 '15 at 15:05
  • Addedd in my response. – RichardK Mar 23 '15 at 15:42
  • Thank you! You are real BigDecimal master :) –  Mar 23 '15 at 16:01
  • Thanks, but this has nothing to do with BigDecimal - it's just a String operation :) It's always good to know basic String operations - it helps a lot. – RichardK Mar 24 '15 at 09:18