Nineteen ninety-nine, minus a cent
A medium Java puzzle in the floating point and money family. One line below contains a real bug. Try to spot it first, then read why it fails and how to fix it.
Highlighted: line 3. Play this one as a puzzle without the answer.
What is wrong
19.99 * 100 evaluates to 1998.9999999999998, and a cast to int truncates it to 1998. 0.29 * 100 gives 28.999999999999996 and becomes 28. Truncation turns tiny floating point errors into visible one-cent differences.
The fix
How to avoid it next time
Round rather than truncate when converting, and avoid doubles for money entirely.
Want the background? Read Primitive types and floating point in the Java concepts library.
About floating point and money
Binary floating point cannot represent most decimal fractions exactly, so equality checks and money calculations with double drift. BigDecimal needs its own care: construct it from strings and always give a scale and rounding mode.
In code review: Flag double or float used for currency, and any == or != on floating point. Check how BigDecimal values are created and rounded.
More puzzles in this family
- #67: Point one plus point two (easy)
- #68: A hundred dimes that do not make ten dollars (medium)
- #69: BigDecimal made from a double (medium)
- #70: One third throws (medium)
- #71: NaN is not equal to itself (hard)
Frequently asked questions
What is the bug in "Nineteen ninety-nine, minus a cent"?
19.99 * 100 evaluates to 1998.9999999999998, and a cast to int truncates it to 1998. 0.29 * 100 gives 28.999999999999996 and becomes 28. Truncation turns tiny floating point errors into visible one-cent differences. The faulty line is line 3: return (int) (price * 100);
How do I fix it?
Replace it with: return Math.round(price * 100); // better: BigDecimal.valueOf(price).movePointRight(2).intValueExact(). Round rather than truncate when converting, and avoid doubles for money entirely.
How do I catch floating point and money in code review?
Flag double or float used for currency, and any == or != on floating point. Check how BigDecimal values are created and rounded.
Is there a new puzzle every day?
Yes. The daily Spot the Bug puzzle picks one of these snippets for each UTC day, with the difficulty set by the weekday. Your streak is stored only in your browser.