Why double Is Inaccurate and How to Use BigDecimal Correctly in Java
This article explains why double precision numbers cannot represent many decimal values exactly, how BigDecimal achieves precise arithmetic through unscaled values and scale, and the proper ways to construct BigDecimal objects to avoid precision loss in Java applications.
BigDecimal, a type from the
java.mathpackage, is widely used for precise arithmetic in financial, e‑commerce, and payment systems. However, merely using
BigDecimaldoes not guarantee accuracy if it is created incorrectly.
Why double Is Inaccurate
Computers operate in binary, so all numbers must be converted to binary for storage. While integer conversion is straightforward, many decimal fractions cannot be represented exactly in binary; for example, 0.1 becomes an infinite repeating binary fraction (0.0001100110011…). Consequently, double values are approximations, leading to precision errors.
The IEEE‑754 standard defines floating‑point representations, including 32‑bit single precision (float) and 64‑bit double precision (double). In Java,
floatand
doublestore these approximations, which is why double‑based calculations can be imprecise.
How BigDecimal Ensures Precision
Internally, a
BigDecimalconsists of an unscaled value and a scale . The scale (accessible via
scale()) indicates the number of digits to the right of the decimal point when non‑negative, or the power of ten to multiply when negative.
<code>public class BigDecimal extends Number implements Comparable<BigDecimal> {
private final BigInteger intVal;
private final int scale;
private final transient long intCompact;
}</code>For example, the number 123.123 is stored with an unscaled value of 123123 and a scale of 3. This representation allows exact storage of values like 0.1, which would otherwise be impossible with binary floating‑point.
Problems with BigDecimal(double)
Creating a
BigDecimalfrom a double inherits the double’s approximation. For instance,
new BigDecimal(0.1)yields a value of 0.1000000000000000055511151231257827021181583404541015625, losing the intended precision.
Creating Precise BigDecimal Instances
The reliable way to obtain an exact
BigDecimalis to use a
Stringconstructor or
BigDecimal.valueOf:
<code>BigDecimal recommend1 = new BigDecimal("0.1");
BigDecimal recommend2 = BigDecimal.valueOf(0.1);
</code>Although
valueOfinternally calls
Double.toString, it returns a canonical string representation that preserves the intended decimal value, avoiding the precision loss seen with the direct double constructor.
Summary
Because computers store numbers in binary, many decimal fractions cannot be represented exactly, causing double‑based calculations to be approximate.
BigDecimalovercomes this by storing an unscaled integer and a scale, enabling exact decimal arithmetic. To maintain precision, always create
BigDecimalobjects from
Stringvalues or use
BigDecimal.valueOf, never from a double directly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.