Retain precision of double in Java with BigDecimal

Kirtan Thakkar

Kirtan Thakkar

Life is all about learning

If you have ever worked with the double values when you need precision, you might have came across a weird issue where you lost the precision of your value with a very little number. Like, when you add 0.1 3 times you get 0.30000000000000004 instead of 0.3.

Here are some examples:

5.6 --- 5.8: 11.399999999999999

0.1 --- 0.1 + 0.1: 0.30000000000000004

1 - 0.33: 0.6699999999999999

(For more details on why this happens, refer to this Stack Overflow answer)

So, Java has a BigDecimal class which can solve this issue. I have made a small program, from which you can understand how you can get your precision right.

You can run the program and analyze the output after each print statement, to get the better understanding.

Here is the code:

HelloWorld.java
import java.math.*;
public class HelloWorld {
public static void main(String[] args) {
// Double precision issue
double d1 = 0.01;
print("d1 = " + d1);
double d2 = 33.33;
print("d2 = " + d2);
double d3 = d2 + d1;
print("d3 = d2+d = " + d3);
double d4 = 33.34;
print("d4 = " + d4);
// Let's work for BigDecimal
BigDecimal bd1 = new BigDecimal(0.01);
print("bd1 = " + bd1.doubleValue());
BigDecimal bd2 = new BigDecimal(33.33);
print("bd2 = " + bd2.doubleValue());
BigDecimal bd3 = new BigDecimal(33.34);
print("bd3 = " + bd3.doubleValue());
BigDecimal bd4 = new BigDecimal(33.33 + 0.01);
print("bd4 = " + bd4.doubleValue());
BigDecimal bd5 = new BigDecimal(String.format("%.2f", 33.33 + 0.01));
print("bd5 = " + bd5.doubleValue());
// Provide values in String in BigDecimal for better precision
// if you already have value in double like shown below
double d11 = 0.1 + 0.1 + 0.1;
print("d11 = " + d11);
BigDecimal bd11 = new BigDecimal(String.valueOf(d11)); // You already lost the precision
print("bd11 = " + bd11.doubleValue());
/* Convert to string as per your needed precision like 2 for
example when you might have lost the precision */
BigDecimal bd12 = new BigDecimal(String.format("%.2f", d11));
print("bd12 = " + bd12);
// Or make sure to do that before addition in double
double d21 = 0.1;
BigDecimal bd21 = new BigDecimal(String.valueOf(d21));
BigDecimal bd22 = bd21.add(bd21).add(bd21);
print("bd21 = " + bd21.doubleValue() + ", bd22 = " + bd22.doubleValue());
}
public static void print(String s) {
System.out.println(s);
}
public static void print(double d) {
System.out.println(d);
}
}

Run your self and play with it for better understanding of when you loose the precision and how to get the correct value before precision is lost.

And Here is the output:

Output
d1 = 0.01
d2 = 33.33
d3 = d2+d = 33.339999999999996
d4 = 33.34
bd1 = 0.01
bd2 = 33.33
bd3 = 33.34
bd4 = 33.339999999999996
bd5 = 33.34
d11 = 0.30000000000000004
bd11 = 0.30000000000000004
bd12 = 0.30
bd21 = 0.1, bd22 = 0.3

When assigning the double value to BigDecimal, make sure you have not already lost your precision. Better create BigDecimal from String value. If you already have double with lost precision, get it formatted in String with "%.2f" (for example) before creating BigDecimal for right value.

It is extremely important to retain the precision when working with the currencies.

Just make sure you don't loose the precision next time.

Happy coding!