Computer Science › Math for Programmers · also in Product Building Blocks
Rounding and Money
Never store money as a float; use integers or decimals.
Also known as: storing money, floating point money, currency rounding
Never store money as a floating-point number. Floats can’t represent most decimal fractions exactly, so tiny errors creep in, and they add up.
0.1 + 0.2 # 0.30000000000000004
sum([0.10] * 10) # 0.9999999999999999
A report that’s off by a cent is a bug that auditors, customers and regulators notice (floating point).
Two safe approaches
1. Integers in the smallest unit (cents, or the currency’s minor unit):
price_cents = 1999 # $19.99
total_cents = price_cents * 3 # 5997, exact
f"${total_cents / 100:.2f}" # format only for display
2. An exact decimal type:
from decimal import Decimal
Decimal("19.99") * 3 # Decimal('59.97')
Create decimals from strings, not floats (Decimal(19.99) copies the float’s error). Databases have NUMERIC / DECIMAL, and Java has BigDecimal.
Rounding
Decide how and when to round, and be consistent.
- Round only at defined points (per line or per invoice), not after every step.
- Pick a rule: half-up is common in invoices, while “banker’s rounding” (half to even) is the default in some libraries. Check what yours does.
- Splitting an amount (a $100 bill across three people) leaves a remainder cent. Decide who gets it, so the parts add up to the whole.
- Percentages and tax produce fractions of cents. Round per your tax rules.
More pitfalls
- Currencies differ: some have no minor unit (JPY), some have three decimals (KWD). Store the currency with the amount (multi-currency handling).
- JSON numbers become floats in JavaScript. Send money as integer cents or a string.
- Never compare floats for equality, and don’t use floats in database money columns.
- Keep an audit trail, and use balanced entries for movements of money (ledger).