Accuracy error in account with Bigdecimal

Asked

Viewed 788 times

3

I have the class below, which shows a different value when I use the calculator. I researched about BigDecimal, but I must be missing something when it comes to presenting the result.

What I have to do is:

4.5% of 8410 = 378.45

But using the class below is only presents 378 . The decimals I am not able to display.

public class Teste {
    public static void main(String[] args) {
        BigDecimal valorInicial = new BigDecimal("8410");
        BigDecimal contanteDivisor = new BigDecimal("100");
        BigDecimal resultDivisao = valorInicial.divide(contanteDivisor, new MathContext(2, RoundingMode.HALF_EVEN));
        BigDecimal resultado = resultDivisao.multiply(new BigDecimal("4.50"));

        System.out.println("Resultado: " + resultado);           
    }    
}

1 answer

6


Remove the MathContext:

public class Teste {
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        BigDecimal valorInicial = new BigDecimal("8410");
        BigDecimal contanteDivisor = new BigDecimal("100");
        BigDecimal resultDivisao = valorInicial.divide(contanteDivisor);
        BigDecimal resultado = resultDivisao.multiply(new BigDecimal("4.50"));

        System.out.println("Resultado: " + resultado);           
    }    
}

When adding new MathContext(2, RoundingMode.HALF_EVEN) on the call of BigDecimal, you are telling it to round the division value to the nearest number by considering up to two digits of accuracy.

With that, when sharing 8410 for 100 according to the excerpt of your code below:

BigDecimal valorInicial = new BigDecimal("8410");
BigDecimal contanteDivisor = new BigDecimal("100");
BigDecimal resultDivisao = valorInicial.divide(contanteDivisor, new MathContext(2, RoundingMode.HALF_EVEN));

resultDivisao should be 84.10, but with rounding using an accuracy of only two digits the result is 84.

See on ideone the difference between the quotients, with and without rounding.

In the next line,

BigDecimal resultado = resultDivisao.multiply(new BigDecimal("4.50"));

You are multiplying in truth 84 for 4.5, resulting in us 378 that your code is displaying, and not in the expected result(84.10 * 4.50 = 378.45);


It is important to note that if the intention of the code was to limit the number of decimal places of the result of the division, the method should be used setScale, because we are talking about scale (digits after comma) and not precision (significant digits).

For this, you can adapt the division line as below:

BigDecimal resultDivisao = valorInicial.divide(contanteDivisor)
        .setScale(2, RoundingMode.HALF_EVEN);

When the result of the split may be an inaccurate number it is necessary to work also with an accuracy to avoid a ArithmeticException. Scale adjustment can be done after splitting:

BigDecimal valorInicial = new BigDecimal("8411");
BigDecimal contanteDivisor = new BigDecimal("101");
BigDecimal resultDivisao = valorInicial
        .divide(contanteDivisor, new MathContext(10, RoundingMode.HALF_EVEN))
        .setScale(2, RoundingMode.HALF_EVEN);

In this case the result of the 8411 for 101 with 10 digit accuracy is 83.27722772. After the scale adjustment the final result is 83.28.

That is, accuracy sets the number of digits to be computed while the scale adjusts the number of decimals.

See the corrected code running on IDEONE.

References:

Documentation: Roundingmode

Documentation: Bigdecimal.setScale

Bigdecimal setScale and round

  • Thank you very much !

Browser other questions tagged

You are not signed in. Login or sign up in order to post.