Quant Memo
Core

Decimal vs Float for Money

Ordinary binary floating point cannot represent most decimal fractions exactly, which is fine for prices and returns but dangerous for cash and P&L — where a decimal type or integer cents avoids the drift.

Prerequisites: Floating-Point Arithmetic and Precision

0.1 + 0.2 in Python returns 0.30000000000000004, not 0.3. That's not a Python bug — it's a fundamental fact about binary floating point, which can represent most integers exactly but only a small subset of decimal fractions exactly, because 0.1 and 0.2 have no finite representation in base 2, the same way 1/31/3 has no finite representation in base 10. For a scientific computation this rounding is usually harmless noise. For a ledger tracking cash to the cent, it is not.

Binary floats cannot exactly represent most decimal fractions, so repeated addition or subtraction of money amounts stored as float accumulates tiny errors that compound over many transactions. Decimal (base-10 arithmetic) or storing money as integer cents avoids this entirely, at some cost in speed and syntactic convenience.

Why it happens

A binary float stores a number as (sign) x (mantissa) x 2exponent2^{exponent}. Just as 1/31/3 has no finite decimal expansion (0.333...), most decimal fractions like 0.1=1/100.1 = 1/10 have no finite binary expansion, because 10 has a prime factor (5) that isn't a power of 2. The stored value is the nearest representable binary float to 0.1 — extremely close, but not exact. Individually this error is around 101710^{-17}, invisible in almost any single calculation. The danger is that it doesn't cancel out on average the way random noise would — it's a deterministic bias for each specific decimal value, and repeated arithmetic on the same biased values can accumulate rather than average away.

float64: sum of 1,000,000 x 0.10 99999.99999999831 Decimal: sum of 1,000,000 x 0.10 100000.00 off by about \$0.0000000017 — small per transaction, but reconciliation and audit systems check to the cent
The float sum drifts by a tiny but nonzero amount after a million additions; Decimal sums exactly because it works in base 10, matching how currency amounts are defined.

Worked example

total = 0.0
for _ in range(1_000_000):
    total += 0.10
print(total)                         # 99999.99999999831 — not exactly 100000.00

from decimal import Decimal
total = Decimal("0.00")
for _ in range(1_000_000):
    total += Decimal("0.10")
print(total)                         # 100000.00, exact

The float loop is off by about $0.0000000017 after a million additions — invisible to a human eye on a single printout, but potentially a real discrepancy in a reconciliation report that checks totals to the cent, or in a system that runs this kind of accumulation continuously over years of trading activity. Decimal, which stores numbers as an exact base-10 digit sequence rather than base-2, has no such drift because 0.10 is exactly representable in base 10.

What this means in practice

The common convention in trading and accounting systems is to avoid the whole class of bug by storing money as integer cents (or the smallest currency unit) rather than as a fractional dollar amount at all — integers add and subtract exactly regardless of base — converting to a display format only at the edges. Where fractional arithmetic genuinely can't be avoided (interest accrual, pro-rating), Decimal is the standard choice for anything touching cash balances, even though it's slower and more verbose than native floats, because correctness trumps speed for ledger entries. Prices, returns, and Greeks, by contrast, are typically fine as ordinary floats — a basis point of relative float error in a volatility estimate is immaterial next to the model uncertainty already present.

Never compare money values with == after any float arithmetic, even between two values that "should" be equal — always compare with a tolerance (abs(a - b) < 1e-9) or, better, avoid the whole issue by working in integer cents or Decimal for anything that will be summed, compared, or reconciled to the cent.

Related concepts

Practice in interviews

Further reading

  • Goldberg, 'What Every Computer Scientist Should Know About Floating-Point Arithmetic' (1991)
  • Python documentation, 'decimal — Decimal fixed point and floating point arithmetic'
ShareTwitterLinkedIn