Using Float And Doube Is A Mistake For Monetary Calculation

Posted By : Kiran Sharma | 29-Nov-2018

As a java programmer we make common calculation mistake by using float and double until we are not familiar with BigDecimal class. While learning java programming we are told that use float and double to store decimal values , but its not told the result of floating number is not exact which makes it uncorrect for calculation where there is need of exact calculation and not the approximate result. For engineering and scientific calculation we use float and double where we require exact result but sometimes it does not give exact result and also sometimes result of floating point may vary from jvm to jvm. Lets check this scenario by using one code mentioned below.

public class BigDecimaDemo {

	public static void main(String[] args) {
		double num1 = 4.2;
		double num2 = 2.9;
		System.out.println("Difference is " + (num1 - num2));
	}
}

        

 

 

 

Output : Difference is 1.3000000000000003

 

 

 

Now before implementing BigDecimal in the same code , lets first discuss some points about BigDecimal.  In java we have BigDecimal class under java.math package. With the help of this class we can perform opertions on double numbers like arithmetic, scaling ,rounding , comparison , format conversion and hashing.It helps in handling  small and large floating point numbers with great precision but here we have to compensate with time complexity a bit.

import java.math.BigDecimal;

public class BigDecimaDemo {

	public static void main(String[] args) {
		BigDecimal num1 = BigDecimal.valueOf(4.2);
		BigDecimal num2 = BigDecimal.valueOf(2.9);
		System.out.println("Difference is " + (num1.subtract(num2)));
	}
}

        

 

 

 

 

 

Output : Difference is 1.3 

 

 

 

From above code example it is now clear that floating point calculation may not be exact at all times and it should not be used where there is need of actual values.

This class implements Comparable interface and its compareTo method is used to do equality comparison of two BigDecimal objects,

Note : compareTo method considers two BigDecimal objects equal which contains equal values but with different scale like 2.0 and 2.00

 

 

 

Incorrect constructor use

---------------------------------------

 

 

 

BigDecimal class has overloaded constructor which takes double value as parameter but its of no use as it will give result same as we use double data type to store value.

import java.math.BigDecimal;

public class BigDecimaDemo {

	public static void main(String[] args) {
		BigDecimal num1 = new BigDecimal(4.2);
		BigDecimal num2 = new BigDecimal(2.9);
		System.out.println("Difference is " + (num1.subtract(num2)));
	}
}

        

 

 

 

Output :

 

Difference is 1.300000000000000266453525910037569701671600341796875 

 

So always use either String constructor or use valueOf method of BigDecimal Class.

 

import java.math.BigDecimal;

public class BigDecimaDemo {

	public static void main(String[] args) {
		BigDecimal num1 = new BigDecimal("4.2");
		BigDecimal num2 = new BigDecimal("2.9");
		System.out.println("Difference is " + (num1.subtract(num2)));
	}
}

        

 

 

 

Output : Difference is 1.3 

 

So what we learnt here -

1. Don't use float and double for exact calculations instead use BigDecimal.

2.Use BigDecimal with String constructor.

3.Don't use floating point result  for comparing loop condition.

 

 

 

Initialization

 

BigDecimal num1 = BigDecimal.valueOf(4.2);
        

 

 

 

For ease of intialization BigDecimal provide some predefined constants. 

BigDecimal num1 = BigDecimal.ONE;
BigDecimal num2 = BigDecimal.ZERO;
BigDecimal num3 = BigDecimal.TEN;
        

 

 

 

Mathematical Operations 

BigDecimal num1 = BigDecimal.valueOf(4.8);
BigDecimal num2 = BigDecimal.valueOf(2.4);
System.out.println("Difference is " + (num1.subtract(num2)));
System.out.println("Addition is " + (num1.add(num2))); 
System.out.println("Multiplication is " + (num1.multiply(num2)));
System.out.println("Division is " + (num2.divide(num1)));

 

Output :

 

Difference is 2.4
Addition is 7.2
Multiplication is 11.52
Division is 0.5 

 

 

 

Comparison

BigDecimal x = BigDecimal.valueOf(2.0);
		BigDecimal y = BigDecimal.valueOf(2.00);

		if (x == y) {
			System.out.println("x == y");
		}
		if (x.compareTo(y) == 0) {
			System.out.println("x and y are equal"); // output
		}
        

 

 

 

Output: x and y are equal

 

 

 

Rounding and Scaling

 

 

 

1. BigDecimal has ability to specify a scale which shows the number of digits after the decimal place. To do this use setScale method.

2. BigDecimal has the ability to round of some value using its defined method.

 

Its a good practivce to use rounding mode along with the scale.

 

	BigDecimal x = BigDecimal.valueOf(2.34);
		System.out.println("Round of value " + x.setScale(1)); 
        

 

 

Output :

 

Exception in thread "main" java.lang.ArithmeticException: Rounding necessary
    at java.math.BigDecimal.commonNeedIncrement(BigDecimal.java:4148)
    at java.math.BigDecimal.needIncrement(BigDecimal.java:4204)
    at java.math.BigDecimal.divideAndRound(BigDecimal.java:4112)
    at java.math.BigDecimal.setScale(BigDecimal.java:2452)
    at java.math.BigDecimal.setScale(BigDecimal.java:2512)
    at BigDecimaDemo.main(BigDecimaDemo.java:7)

 

 

 

Here it throws exception as scaling is not possible without round off and as it does not know how to round of this number is throwing exception. 

 

There are 8 rounding modes available.

 

BigDecimal.ROUND_CEILING 
BigDecimal.ROUND_DOWN 
BigDecimal.ROUND_FLOOR 
BigDecimal.ROUND_HALF_DOWN
BigDecimal.ROUND_HALF_EVEN
BigDecimal.ROUND_HALF_UP 
BigDecimal.ROUND_UNNECESSARY
BigDecimal.ROUND_UP
		
        

 

import java.math.BigDecimal;
import java.math.RoundingMode;

public class BigDecimaDemo {
	public static void main(String[] args) {
		BigDecimal num1 = BigDecimal.valueOf(21);
		BigDecimal num2 = BigDecimal.valueOf(5);
		System.out.println("Result is : " + num1.divide(num2));
		System.out.println("Result with CEILING is : " + num1.divide(num2, RoundingMode.CEILING));
		System.out.println("Result with DOWN is : " + num1.divide(num2, RoundingMode.DOWN));
	}
}
    

Output :

Result is : 4.2
Result with CEILING is : 5
Result with DOWN is : 4

 

BigDecimal num1 = BigDecimal.valueOf(21.987);
		System.out.println("Result is : " + num1.setScale(1,RoundingMode.CEILING));
		System.out.println("Result is : " + num1.setScale(2,RoundingMode.DOWN));
        

 

 

 

Output :

 

Result is : 22.0
Result is : 21.98 

 

 

 

 

About Author

Author Image
Kiran Sharma

Kiran has good knowledge of java with Servlets, JSPs, Spring, and hibernate frameworks. She is very honest towards her work. Her hobby is listening to music.

Request for Proposal

Name is required

Comment is required

Sending message..