Java BigDecimal precision problems
Solution 1:
What you actually want is
new BigDecimal("0.1")
.add(new BigDecimal("0.1"))
.add(new BigDecimal("0.1"));
The new BigDecimal(double)
constructor gets all the imprecision of the double
, so by the time you've said 0.1
, you've already introduced the rounding error. Using the String
constructor avoids the rounding error associated with going via the double
.
Solution 2:
First never, never use the double constructor of BigDecimal. It may be the right thing in a few situations but mostly it isn't
If you can control your input use the BigDecimal String constructor as was already proposed. That way you get exactly what you want. If you already have a double (can happen after all), don't use the double constructor but instead the static valueOf
method. That has the nice advantage that we get the cannonical representation of the double which mitigates the problem at least.. and the result is usually much more intuitive.
Solution 3:
This is not a problem of Java, but rather a problem of computers generally. The core problem lies in the conversion from decimal format (human format) to binary format (computer format). Some numbers in decimal format are not representable in binary format without infinite repeating decimals.
For example, 0.3 decimal is 0.01001100... binary But a computer has a limited "slots" (bits) to save a number, so it cannot save all the whole infinite representation. It saves only 0.01001100110011001100 (for example). But that number in decimal is no longer 0.3, but 0.30000000000000004 instead.
Solution 4:
Try this:
BigDecimal sum = new BigDecimal(0.1).add(new BigDecimal(0.1)).add(new BigDecimal(0.1));
EDIT: Actually, looking over the Javadoc, this will have the same problem as the original. The constructor BigDecimal(double)
will make a BigDecimal corresponding to the exact floating-point representation of 0.1, which is not exactly equal to 0.1.
This, however, gives the exact result, since integers CAN always be expressed exactly in floating-point representation:
BigDecimal one = new BigDecimal(1);
BigDecimal oneTenth = one.divide(new BigDecimal(10));
BigDecimal sum = oneTenth.add(oneTenth).add(oneTenth);