Why BigDecimal Can Still Lose Precision and How to Use It Correctly in Java

This article explains how floating‑point arithmetic in Java leads to precision loss, shows that even BigDecimal can suffer the same issue when misused, and provides proper construction methods and a utility class to ensure accurate monetary calculations.

Programmer DD
Programmer DD
Programmer DD
Why BigDecimal Can Still Lose Precision and How to Use It Correctly in Java

It is common practice to use BigDecimal for monetary calculations because floating‑point types such as float and double lose precision.

However, BigDecimal itself can also lose precision if instantiated incorrectly, so understanding its behavior is essential.

Floating‑point example:

System.out.println(0.05 + 0.01);
System.out.println(1.0 - 0.42);
System.out.println(4.015 * 100);
System.out.println(123.3 / 100);

Output:

0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

The loss of precision becomes critical in e‑commerce scenarios, where the sum of 0.05 and 0.01 is represented as 0.060000000000000005, potentially preventing a purchase.

Precision details: float provides 6‑7 significant digits, while double provides 15‑16.

API – Constructors

BigDecimal(int)       // creates a BigDecimal from an int
BigDecimal(double)    // creates a BigDecimal from a double (may lose precision)
BigDecimal(long)      // creates a BigDecimal from a long
BigDecimal(String)    // creates a BigDecimal from a String (recommended for exact values)

API – Methods

add(BigDecimal)       // addition
subtract(BigDecimal) // subtraction
multiply(BigDecimal) // multiplication
divide(BigDecimal)   // division
toString()            // converts to String
doubleValue()         // converts to double
floatValue()          // converts to float
longValue()           // converts to long
intValue()            // converts to int

Using the double constructor still suffers from precision loss because binary floating‑point cannot represent many decimal fractions exactly. For example:

BigDecimal a = new BigDecimal(1.01);
BigDecimal b = new BigDecimal(1.02);
BigDecimal c = new BigDecimal("1.01");
BigDecimal d = new BigDecimal("1.02");
System.out.println(a.add(b)); // 2.0300000000000000266453525910037569701671600341796875
System.out.println(c.add(d)); // 2.03

The discrepancy originates from the underlying binary representation of the numbers. While long can store up to 19 exact digits, double is limited to about 16, and any higher precision requires BigInteger.

Therefore, when performing monetary calculations, always instantiate BigDecimal with the String constructor to avoid hidden precision errors. This recommendation is also echoed in Effective Java and MySQL best‑practice guides.

Because BigDecimal is an object, arithmetic operators (+, -, *, /) cannot be used directly; you must call the corresponding methods, and the method arguments must also be BigDecimal instances.

Below is a utility class that simplifies basic arithmetic on double values by converting them to BigDecimal via Double.toString and then applying the appropriate methods:

public class BigDecimalUtil {
    private BigDecimalUtil() {}

    public static BigDecimal add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2);
    }

    public static BigDecimal sub(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2);
    }

    public static BigDecimal mul(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2);
    }

    public static BigDecimal div(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP); // keep two decimal places
    }
}

This utility provides accurate addition, subtraction, multiplication, and division for double values by leveraging BigDecimal internally.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BackendjavaprecisionBigDecimalutilityfloating-point
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.