Understanding Java BigDecimal Precision Mechanism
The article explains how Java’s BigDecimal class maintains exact financial precision by storing numbers as an unscaled integer and a scale, scaling operands to a common decimal place, performing integer arithmetic—including handling differing scales—and finally reconstructing a correctly scaled result.
In the financial domain, BigDecimal is often used to guarantee numerical precision. This article explains why BigDecimal can avoid precision loss.
Class introduction
The BigDecimal class is declared as follows, with key fields such as intVal (unscaled value), scale (number of decimal places), precision , stringCache , and intCompact :
public class BigDecimal extends Number implements Comparable<BigDecimal> {
// unscaled value
private final BigInteger intVal;
// scale (decimal places)
private final int scale;
// precision (unused here)
private transient int precision;
// cached string representation
private transient String stringCache;
// compact long representation
private final transient long intCompact;
}Example from a test method
The following 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);
}After calling BigDecimal.valueOf(2.36) , debugging shows that the internal fields are populated with the unscaled value 236 and scale 2.
add method source code
/**
* Returns a BigDecimal whose value is (this + augend),
* and whose scale is max(this.scale(), augend.scale()).
*/
public BigDecimal add(BigDecimal augend) {
if (this.intCompact != INFLATED) {
if (augend.intCompact != INFLATED) {
return add(this.intCompact, this.scale, augend.intCompact, augend.scale);
} else {
return add(this.intCompact, this.scale, augend.intVal, augend.scale);
}
} else {
if (augend.intCompact != INFLATED) {
return add(augend.intCompact, augend.scale, this.intVal, this.scale);
} else {
return add(this.intVal, this.scale, augend.intVal, augend.scale);
}
}
}The private static add method that receives raw long values handles the scale difference:
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. The method first computes the scale difference (1) and follows the branch that scales the second operand, performs integer addition, and finally constructs a new BigDecimal with the appropriate scale.
A simpler overload adds two long values when scales are equal:
private static BigDecimal add(long xs, long ys, int scale) {
long sum = add(xs, ys);
if (sum != INFLATED)
return BigDecimal.valueOf(sum, scale);
return new BigDecimal(BigInteger.valueOf(xs).add(ys), scale);
}Conclusion
BigDecimal preserves precision by scaling numbers to a long (or BigInteger) representation, performing integer arithmetic, and then applying the original scale to produce the final result.
Java Tech Enthusiast
Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!
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.