Backend Development 9 min read

Understanding Precision Loss in Java's BigDecimal and Proper Usage

The article explains why floating‑point arithmetic in Java loses precision, demonstrates how even BigDecimal can suffer when constructed from double values, and shows the correct practice of using the BigDecimal(String) constructor together with utility methods to perform accurate monetary calculations.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Understanding Precision Loss in Java's BigDecimal and Proper Usage

When monetary calculations are required, using float or double leads to precision loss, so developers are advised to use BigDecimal . The article starts by showing typical floating‑point errors with simple arithmetic.

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);

The output demonstrates values such as 0.060000000000000005 and 401.49999999999994 , illustrating why e‑commerce systems may encounter ordering or reconciliation problems.

Java's float provides about 6‑7 significant digits, while double offers 15‑16 digits, still insufficient for exact monetary representation.

API

Constructors:

BigDecimal(int)       // creates from an int value
BigDecimal(double)    // creates from a double value (may lose precision)
BigDecimal(long)      // creates from a long value
BigDecimal(String)    // creates from a string representation (recommended)

Methods:

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

Even BigDecimal can lose precision if instantiated with a double . The following example shows the problem:

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));
System.out.println(c.add(d));

Output:

2.0300000000000000266453525910037569701671600341796875
2.03

The double‑based constructor yields a long, inaccurate result, while the String constructor produces the exact value. This occurs because binary floating‑point cannot represent many decimal fractions precisely; the underlying hardware stores numbers in limited bits (19 digits for long , about 16 for double ).

Therefore, for commercial calculations one should always create BigDecimal objects with the BigDecimal(String) constructor, as recommended by Effective Java and MySQL guidelines.

The JDK source comment further explains that the BigDecimal(double) constructor is unpredictable and that converting the double to a string first yields an exact conversion:

* The results of this constructor can be somewhat unpredictable.
* One might assume that writing {@code new BigDecimal(0.1)} creates a BigDecimal exactly equal to 0.1,
* but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625.
* When a double must be used as a source for a BigDecimal, use BigDecimal.valueOf(double) instead.

Because BigDecimal is an object, arithmetic operators cannot be used directly; one must call the appropriate methods, and the method arguments must also be BigDecimal instances.

To simplify usage, the article provides a utility class:

/**
 * @author Ji YongGuang.
 * @date 19:50 2017/12/14.
 */
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));
        // retain two decimal places, round half up
        return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);
    }
}

This utility offers static methods for addition, subtraction, multiplication, and division of double values while preserving precision by converting them to BigDecimal via Double.toString .

JavaBackend DevelopmentPrecisionBigDecimalFloating PointMonetary Calculations
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login 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.