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.

Leave a comment

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.