Fundamentals 6 min read

Why Does BigDecimal Preserve Precision? Inside Java’s Decimal Engine

This article explains how Java's BigDecimal class maintains exact decimal precision by scaling numbers to integers, detailing its internal fields, the add method implementation, and a concrete example that demonstrates the underlying computation steps.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Why Does BigDecimal Preserve Precision? Inside Java’s Decimal Engine

Class Overview

BigDecimal is declared as

public class BigDecimal extends Number implements Comparable<BigDecimal> { ... }

with fields such as private final BigInteger intVal;, private final int scale;, private transient int precision;, private transient String stringCache;, and private final transient long intCompact;.

Example

A JUnit test creates two BigDecimal instances and adds them:

@Test
public void testBigDecimal() {
    BigDecimal bigDecimal1 = BigDecimal.valueOf(2.36);
    BigDecimal bigDecimal2 = BigDecimal.valueOf(3.5);
    BigDecimal resDecimal = bigDecimal1.add(bigDecimal2);
    System.out.println(resDecimal);
}

Debugging after BigDecimal.valueOf(2.36) shows the internal fields being populated.

Debug view of BigDecimal fields
Debug view of BigDecimal fields

add Method Details

The add(BigDecimal augend) method selects a scale and delegates to private static overloads. The core overload

private static BigDecimal add(final long xs, int scale1, final long ys, int scale2)

first computes the scale difference and then either aligns the numbers by scaling or falls back to BigInteger arithmetic.

private static BigDecimal add(final long xs, int scale1, final long ys, int scale2) {
    long sdiff = (long) scale1 - scale2;
    if (sdiff == 0) {
        return add(xs, ys, scale1);
    } else if (sdiff < 0) {
        int raise = checkScale(xs, -sdiff);
        long scaledX = longMultiplyPowerTen(xs, raise);
        if (scaledX != INFLATED) {
            return add(scaledX, ys, scale2);
        } else {
            BigInteger bigsum = bigMultiplyPowerTen(xs, raise).add(ys);
            return ((xs ^ ys) >= 0) ? new BigDecimal(bigsum, INFLATED, scale2, 0)
                                    : valueOf(bigsum, scale2, 0);
        }
    } else {
        int raise = checkScale(ys, sdiff);
        long scaledY = longMultiplyPowerTen(ys, raise);
        if (scaledY != INFLATED) {
            return add(xs, scaledY, scale1);
        } else {
            BigInteger bigsum = bigMultiplyPowerTen(ys, raise).add(xs);
            return ((xs ^ ys) >= 0) ? new BigDecimal(bigsum, INFLATED, scale1, 0)
                                    : valueOf(bigsum, scale1, 0);
        }
    }
}

In the example, the parameters are xs=236, scale1=2, ys=35, scale2=1, leading to the scaling path that multiplies the smaller operand by 10.

Scale adjustment illustration
Scale adjustment illustration

Conclusion

BigDecimal preserves precision by converting decimal numbers into scaled long integers (or BigInteger when overflow occurs), performing integer arithmetic, and then applying the original scale to produce the final result.

JavaPrecisionBigDecimalfinance
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

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.