Search code examples
javabigdecimal

How to deal with rouding in BigDecimal in Java


I have this code to get a percentage:

final BigDecimal price = BigDecimal.valueOf(215).setScale(2, BigDecimal.ROUND_HALF_EVEN);
final BigDecimal daysOfThisReservation = BigDecimal.valueOf(3).setScale(2, BigDecimal.ROUND_HALF_EVEN);

final BigDecimal dayPrice = price.divide(daysOfThisReservation, BigDecimal.ROUND_HALF_EVEN).setScale(2, BigDecimal.ROUND_HALF_EVEN);

System.out.println(dayPrice); //71.67
System.out.println(dayPrice.multiply(daysOfThisReservation).setScale(2, BigDecimal.ROUND_HALF_EVEN)); //215.01

I have a reservation that costs $215.00, this reservation has 3 per day, so, the price is $71.67.

If I try to get the original value again, I have some problems with rounding, 71.67 * 3 = 215.01

How to deal with this kind of problem?


Solution

  • My feeling is that the problem here is not one of throwing away the original price, but rather of throwing way valuable information by truncating fractional values to two decimal places. If you kept even one more decimal place, you wouldn't have this problem.

    Here's an example that keeps 6 places of precision to allow enough precision for doing hundreds of operations on values for which I eventually want only two significant decimal places. You will never have rounding problems with 6 decimal places if you only care in the end about 2 places.

    This code keeps 6 places except when printing the single-day price, at which point it rounds to 2 places.

    final BigDecimal price = BigDecimal.valueOf(215).setScale(6, BigDecimal.ROUND_HALF_EVEN);
    final BigDecimal daysOfThisReservation = BigDecimal.valueOf(3).setScale(6, BigDecimal.ROUND_HALF_EVEN);
    
    final BigDecimal dayPrice = price.divide(daysOfThisReservation, BigDecimal.ROUND_HALF_EVEN).setScale(6, BigDecimal.ROUND_HALF_EVEN);
    
    System.out.println(dayPrice.setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(dayPrice.multiply(daysOfThisReservation).setScale(2, BigDecimal.ROUND_HALF_EVEN)); //215.01
    

    Result:

    71.67
    215.00