Why 0.1 + 0.2 is not exactly 0.3, how round() really behaves, and how to show money with exactly two decimals.
About 30 minBeginner4 exercisesFree
You will be able to
Explain why some decimal numbers cannot be stored exactly as floats
Round values with round() and predict its result for halfway cases
Display money with exactly two decimal places using :.2f
Convert an amount to whole halalas (cents) without losing a unit
Recognise when Decimal is the better tool for money
Imagine a café till that adds a 0.10 SAR sugar sachet to a 0.20 SAR paper cup and prints the total. You expect 0.3. Python prints 0.30000000000000004. Nothing is broken: this is how computers store decimal numbers, and every language that uses floats (JavaScript, Java, C, Excel internally) does the same.
As soon as your programs handle prices, measurements or averages, you need to know where these tiny errors come from and how to keep them out of what people see.
The famous surprise
cup =0.20
sugar =0.10
total = cup + sugar
print(total)print(0.1+0.2+0.3)
Try it: Try 0.5 + 0.25. Do you get an exact answer this time?
Why it happens
A float is stored in binary (base 2) using a fixed number of bits. Some fractions fit neatly in binary: 0.5 is one half, 0.25 is one quarter, so they are stored exactly. But 0.1 is one tenth, and one tenth has no exact binary form — in the same way that one third has no exact decimal form (0.3333… goes on forever).
So Python stores the closest float it can to 0.1. That value is off by about 0.00000000000000000555. Usually Python hides this when printing, but when you add two slightly-off values the error can become big enough to show.
Key ideas:
The error is tiny (around the 16th or 17th significant digit) — fine for physics, averages and percentages.
It is not random: the same calculation always gives the same result.
It matters most when you display values or need exact money totals.
Rounding with round()
round(number, ndigits) returns the number rounded to ndigits decimal places. With no second argument it rounds to a whole number and returns an int.
Halfway values go to the even neighbour.round(2.5) is 2 and round(3.5) is 4. This is called banker's rounding; it avoids always pushing totals upwards when many halves are rounded.
Some "halfway" values aren't really halfway.round(2.675, 2) gives 2.67, because the float stored for 2.675 is actually a hair below 2.675.
Showing money: round for calculations, format for display
round(11.5, 2) is still 11.5 — a float has no idea you wanted two decimals. To display exactly two decimal places, use a format specification inside an f-string:
price =11.5print(f"{price:.2f} SAR")# 11.50 SAR
:.2f means "fixed-point, 2 digits after the point". It also rounds for display, so f"{0.1 + 0.2:.2f}" shows 0.30. You'll learn many more format codes in f-strings and formatting; for now :.2f is the one you need.
A good habit: round() the values you store (so later calculations use clean amounts) and format with :.2f when you print.
VAT on a price: store a rounded value, print a formatted one
price =float(input("Price before VAT: "))
VAT_RATE =0.15
with_vat = price *(1+ VAT_RATE)print("Raw result:", with_vat)
with_vat =round(with_vat,2)print(f"Price with VAT: {with_vat:.2f} SAR")
Input given to the program: "19.99"
Try it: Change the stdin price to 10 and compare the raw result with the formatted one.
Counting in whole halalas
One SAR is 100 halalas. Many payment systems store money as a whole number of the smallest unit, because integers are always exact. Converting looks like "multiply by 100", but there's a trap:
int(19.99*100)# 1998 — a halala has gone missing!round(19.99*100)# 1999
19.99 * 100 is 1998.9999999999998, and int()chops off everything after the point instead of rounding. Use round() whenever you turn a float amount into whole units.
When to reach for Decimal
The decimal module stores numbers in base 10, so 0.1 really is 0.1. Create a Decimal from a string, not from a float (a float already carries the error):
Decimal gives exact decimal arithmetic
from decimal import Decimal
print(Decimal("0.10")+ Decimal("0.20"))print(Decimal(0.1))print(Decimal("19.99")*3)
Try it: Change Decimal("0.10") to Decimal(0.10) and look at how long the result becomes.
Use Decimal for accounting software, invoices that must balance to the halala, and anything audited. For everyday calculations — averages, measurements, percentages — floats with round() and :.2f are perfectly fine, and that's what the rest of this track uses.
Guided practice · ●difficulty 1 of 5 · about 4 min
Add VAT to a price
A shop adds 15% VAT to every price. Write a program that:
reads a price with input() (no prompt text — the tests type the values for you) and converts it to a float,
stores the price including VAT, rounded to 2 decimal places, in a variable called total,
prints it with exactly two decimals followed by SAR.
Example: for input 19.99 the program prints
Total: 22.99 SAR
and total is 22.99 (19.99 × 1.15 = 22.9885, rounded).
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Challenge · ●●●difficulty 3 of 5 · about 8 min
Split a payment into instalments
An electronics store lets customers pay in equal monthly instalments. Because of rounding, the final payment absorbs any leftover halalas so that the payments add up exactly to the price.
Read two lines with input() (no prompt text): the price (a float) and the number of months (an int). Then:
monthly = price ÷ months, rounded to 2 places,
final = price minus monthly × (months − 1), rounded to 2 places.
Print both with two decimals. For inputs 1000 and 3:
Monthly: 333.33 SAR
Final payment: 333.34 SAR
(333.33 + 333.33 + 333.34 = 1000.00.)
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Edge cases · ●●difficulty 2 of 5 · about 5 min
Convert SAR to whole halalas
A payment terminal works in whole halalas (1 SAR = 100 halalas) and needs an int.
Read an amount in SAR with input() (no prompt text) as a float. Store the number of halalas as an int in a variable called halalas, then print it like this. For input 19.99:
1999 halalas
Be careful: some amounts multiply out to values like 1998.9999999999998. The terminal must never lose a halala.
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Debugging · ●●difficulty 2 of 5 · about 6 min
Fix the discount receipt
A stationery shop's receipt program reads a unit price and a quantity, then applies a 10% discount. For a price of 19.99 and quantity 3 the owner expects:
Subtotal: 59.97 SAR
Total after 10% off: 53.97 SAR
Instead the program prints Subtotal: 60.00 SAR and a strange 5.4e+01 for the total. Find and fix the bugs. Keep the variable names subtotal and total, and keep both of them rounded to 2 places. (The program reads its values with input(), no prompt text.)
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Summary
Floats are stored in binary, so values like 0.1 are close approximations and tiny errors can appear.
round(x, n) rounds to n decimal places; round(x) returns an int, and exact halves go to the even neighbour.
Store rounded values with round(); display money with f"{x:.2f}".
Convert amounts to whole units with round(amount * 100), never int(), which truncates.
Use Decimal (created from strings) when money must balance exactly, such as in accounting.