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.
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.
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.
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.
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!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
