Why this matters

The bug. Decimal fractions like 0.99 don't have exact binary representations. 19.99 is stored as a value very slightly less than 19.99, and * 100 propagates the error. int() truncates *toward zero*, so int(1998.9999999999998) is 1998 — not 1999. Across millions of orders, you underbill by real money.

The fix. round() is half-to-even (banker's rounding) and handles the drift correctly. The really-correct fix is to never use float for money: parse strings into Decimal at the API boundary and stay in cents-as-int internally.

War story. This is the bug behind the apocryphal 'salami slicing' scams — except those usually exploited rounding *up* with the fractional cent retained. This version is the opposite: you accidentally give the cent away.

Review heuristic

Money in a float or double is a bug. Equality on a float is a bug. Accumulation in a long-running average without a corrective term is a slow-burning bug. Each one needs a deliberate justification or a type change.

External reference: CWE-682: Incorrect Calculation.