Integer and float precision on money
Money in a float is a rounding error waiting for a big enough order.
What it looks like
- An amount held as a fractional major unit rather than an integer minor unit.
Math.roundbecomingMath.truncorMath.floor, or a rounding step removed entirely.- A percentage applied by multiplying before dividing, or after.
Why it survives review
Amounts that divide exactly behave identically, and those are the amounts anybody writes a test with — £10.00, 20% tax, a round answer. The error is a fraction of a penny per line, which is invisible until it is summed over a day's orders and compared against a bank statement.
How to see it
- Check money is an integer number of minor units everywhere, and that the only place it becomes a decimal is where it is formatted for display.
- For every rounding call, ask which way it rounds and whether the finance team agrees.
- Check the order of operations:
(amount * rate) / 10000andamount * (rate / 10000)do not agree in floating point.
A minimal pair
Correct
return Math.round((subtotal * rate) / 10000);
Defective
return Math.trunc((subtotal * rate) / 10000);
A subtotal of 333 at 3.33% gives 11 in the correct build and 11 in the defective one — until the fraction lands above a half.
Practise it
2 diffs in the corpus carry this class. They are not listed, because knowing which diff contains what would make finding it a comprehension question about this page.
Go to the exercises