Skip to content

Taxonomy

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.round becoming Math.trunc or Math.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

  1. 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.
  2. For every rounding call, ask which way it rounds and whether the finance team agrees.
  3. Check the order of operations: (amount * rate) / 10000 and amount * (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