If you have used float or double for monetary calculation in Java, you must have noticed and said why is the calculation wrong. We’ll get ‘100.00999999999999’, if we subtract 0.01 from 100.02 (double type). This result is unacceptable in monetary calculation. So the question arises, why?

Well, this article can shed some lights on our why! Working with Money in Java

Let’s have a look at code that will calculate output for adding and subtracting using double.

public class DoubleIsBadForAmount { double amount = 100.00; double modifier = 0.01; public void doubleAdd() { for (int i = 0; i < 5; i++) { amount = amount - modifier; System.out.println(amount); } } public void doubleSubtract() { amount = 100.00; for (int i = 0; i < 5; i++) { amount = amount + modifier; System.out.println(amount); } } public static void main(String[] args) { DoubleIsBadForAmount main = new DoubleIsBadForAmount(); main.doubleAdd(); main.doubleSubtract(); } }

The output of above code :

99.99 99.97999999999999 99.96999999999998 99.95999999999998 99.94999999999997 100.01 100.02000000000001 100.03000000000002 100.04000000000002 100.05000000000003

We can see, that precision is lost, as the output is not as expected. Having ‘99.97999999999999’ as amount is not what we want. So, the solution is to use BigDecimal, to represent monetary values. The BigDecimal is slower in calculation than primitive double type, which’ll be case, if application involves heavy calculations.

public class BigDecimalForAmount { double amount = 100.00; double modifier = 0.01; public void doubleAdd() { BigDecimal sum = new BigDecimal(amount); BigDecimal mod = new BigDecimal(modifier); for (int i = 0; i < 5; i++) { sum = sum.add(mod); System.out.println(BigDecimalForAmount.roundHalfEven(sum.doubleValue())); } } public void doubleSubtract() { amount = 100.00; BigDecimal sum = new BigDecimal(amount); BigDecimal mod = new BigDecimal(modifier); for (int i = 0; i < 5; i++) { sum = sum.subtract(mod); System.out.println(BigDecimalForAmount.roundHalfEven(sum.doubleValue())); } } private static double roundHalfEven(double amount) { BigDecimal amt = new BigDecimal(amount); amt = amt.divide(new BigDecimal(1), 2, BigDecimal.ROUND_HALF_EVEN); return amt.doubleValue(); } public static void main(String[] args) { BigDecimalForAmount main = new BigDecimalForAmount(); main.doubleAdd(); main.doubleSubtract(); } }

In above code we used BigDecimal with rounding to get precise result and the output is as expected.

Output :

100.01 100.02 100.03 100.04 100.05 99.99 99.98 99.97 99.96 99.95

Conclusion : using float or double for monetary calculation is a big NO, while BigDecimal is mostly recommended.