Search code examples
javaandroidbigdecimal

Unexpected results for mathematical operations


While performing mathematical operations to develop an android application for a simple calculator, resulted in strange results for subtraction and division operation. Other operations goes well with the inputs provided. In my research for precision handling, came across BigDecimal class that lessen down my errors.

Certain operations like subtraction and division have not yielded proper results. I am providing with the code snippet here.

.
.
.
String answer = "";
BigDecimal bigDecimal1, bigDecimal2;
BigDecimal bigDecimalResult;
String operation = "";
.
.
.

                case R.id.button_substraction:
                    bigDecimal1 = new BigDecimal(answer);
                    operation = "-";
                    answer = "";
                    textViewAnswer.setText(buttonSubstraction.getText().toString());
                    break;
                case R.id.button_division:
                    bigDecimal1 = new BigDecimal(answer);
                    operation = "/";
                    answer = "";
                    textViewAnswer.setText(buttonDivision.getText().toString());
                    break;
                case R.id.button_equal:
                    bigDecimal2 = new BigDecimal(answer);
                    answer = "";
                    switch (operation) {
                           .
                           .

                        case "-":
                            bigDecimalResult = (bigDecimal1.subtract(bigDecimal2)).setScale(6,RoundingMode.HALF_UP).stripTrailingZeros();
                            textViewAnswer.setText(bigDecimalResult.toString());
                            break;

                        case "/":
                            bigDecimalResult = (bigDecimal1.divide(bigDecimal2)).setScale(6,RoundingMode.HALF_UP).stripTrailingZeros();
                            textViewAnswer.setText(bigDecimalResult.toString());
                            break;
                    }
.
.
.

Example:

  1. Subtraction

when a number is subtracted from itself, it results 0 with the precision value 6(set in the code) as,

100 - 100 = 0.000000

Even though stripTrailingZeros() is specified.

  1. Division

Attempting to divide

1 / 9

crashes my app.

  • Have I gone wrong with logic implementation ?
  • Does it has something to do with storage representation in memory as BigDecimal class is used ?

Solution

  • Your problem with stripTrailingZeros() not stripping a zero value was fixed in Java 8.
    See JDK-6480539: BigDecimal.stripTrailingZeros() has no effect on zero itself ("0.0")

    Your problem with 1 / 9 crashing your app, is caused by your logic:

    bigDecimalResult = bigDecimal1.divide(bigDecimal2)
                                  .setScale(6, RoundingMode.HALF_UP)
                                  .stripTrailingZeros()
    

    You are trying to set the scale after dividing, but there is no exact value for 1 / 9, so the divide() method throws an exception, as documented in the javadoc.

    Throws ArithmeticException if the exact quotient does not have a terminating decimal expansion

    You should call one of the other overloads of the divide() method:

    bigDecimalResult = bigDecimal1.divide(bigDecimal2, 6, RoundingMode.HALF_UP)
                                  .stripTrailingZeros()
    

    Now, beware result of stripTrailingZeros(). E.g. if result is 100.00000, stripTrailingZeros() will literally strip all the zeros, resulting in 1E+2. That is probably not what you want.

    To get that printed in a more human readable way, you might want to use toPlainString() instead of toString().