runtime
104 / 250
lesson 104 Dates Numbers & Regex · intermediate

Exact money with Decimal

Floats are binary fractions, so `0.1 + 0.2` isn't exactly `0.3`. Decimal does decimal arithmetic exactly, and `quantize` rounds to cents with the rule you choose.

You'll be able to
  • Explain why floats drift with money and why Decimal("0.1") must be built from text
  • Round a Decimal to cents with quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
  • Know that the default rounding is half-to-even, and keep floats and Decimals apart
The idea

Floats store numbers in binary, and most decimal fractions (0.1, 0.2, 0.07) have no exact binary form. The tiny errors are invisible in a single value and show up when you add, compare or round money: a total that should be 0.30 is 0.30000000000000004, and a tax that should round up rounds down.

from decimal import Decimal gives exact decimal numbers. Build them from text: Decimal("0.1") is exactly one tenth, while Decimal(0.1) faithfully copies the float's binary error. Arithmetic between Decimals stays exact.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · Float drift and the exact version
from decimal import Decimal

print(0.1 + 0.2)
print(Decimal("0.1") + Decimal("0.2"))
print(Decimal(0.1))

Multiplying creates more decimal places: a 7% tax on 6.49 is 0.4543. amount.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP) rounds to cents. Name the rule: without it, Decimal rounds half to even (banker's rounding), so 0.125 becomes 0.12, while most receipts expect 0.13.

example-2.py · Sales tax rounded to the cent
from decimal import Decimal, ROUND_HALF_UP

def with_tax(subtotal_text, rate_text):
    subtotal = Decimal(subtotal_text)
    tax = (subtotal * Decimal(rate_text)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
    return subtotal + tax

print(with_tax("6.49", "0.07"))
print(with_tax("66.49", "0.07"))
print(Decimal("0.125").quantize(Decimal("0.01")), Decimal("0.125").quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
example-3.py · Mixing Decimal and float
from decimal import Decimal

price = Decimal("19.99")
print(price + 0.01)

When to use it: prices, tax, invoices, ledgers: anywhere two totals must match to the cent. Floats are fine for measurements (temperatures, distances). Mistakes to avoid: building Decimals from floats, rounding without naming the rule, and rounding each line differently from the total. str(amount) gives text like 43.77 for reports and APIs.

Review
  • Floats are binary approximations; money needs exact decimals.
  • Build Decimals from text: Decimal("19.99"). Don't mix them with floats.
  • Round with quantize(Decimal("0.01"), rounding=...); the default is half to even, receipts usually want half up.
  • Next: finding and checking patterns in text with regular expressions.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Exact money with Decimal — Dates Numbers & Regex · Runtime