Income is 2000, expenses are 1500. What fraction of income was saved?
500 / 2000 = 0.25. So 25%, or 0.25 as a ratio between zero and one.
Exactly. The formula is (income - expenses) / income. A clean first draft:
rate = (income - expenses) / incomeFor (2000, 1500), that's 0.25. Good enough to start — but there are two edges worth handling before you ship it.
Two edges? Floating-point weirdness is one — 0.1 + 0.2 gives 0.30000000000000004. What's the other?
The other is a zero income. Dividing by zero crashes with ZeroDivisionError. Both edges get handled the same way this track has handled them all along — round at the return, guard at the top:
def savings_rate(income, expenses):
if income == 0:
return 0.0
return round((income - expenses) / income, 2)Why round(..., 2) specifically — is two decimals the right resolution for a ratio?
For a ratio between 0 and 1, two decimals gives 1% precision. More than enough for a savings rate — a human reader can't tell the difference between 0.25001 and 0.25. Round at the boundary so the caller gets a clean float.
So every division you write has the same three pieces — guard the denominator, do the math, round once at the return.
That's the shape. Clean arithmetic isn't about clever tricks — it's about checking the edges first and doing one operation at a time, in order.
round()TL;DR: guard the denominator → divide → round once at the return.
(income - expenses) / income — the mathround(x, 2) — 2-decimal cleanupif income == 0: return 0.0 — denominator guard| Placement | Effect |
|---|---|
| Inside a chain of math | compounds rounding errors |
| Once at the return | predictable, clean |
Math first, round last. A ratio between 0 and 1 at 2 decimals is plenty of precision for a savings rate.
Income is 2000, expenses are 1500. What fraction of income was saved?
500 / 2000 = 0.25. So 25%, or 0.25 as a ratio between zero and one.
Exactly. The formula is (income - expenses) / income. A clean first draft:
rate = (income - expenses) / incomeFor (2000, 1500), that's 0.25. Good enough to start — but there are two edges worth handling before you ship it.
Two edges? Floating-point weirdness is one — 0.1 + 0.2 gives 0.30000000000000004. What's the other?
The other is a zero income. Dividing by zero crashes with ZeroDivisionError. Both edges get handled the same way this track has handled them all along — round at the return, guard at the top:
def savings_rate(income, expenses):
if income == 0:
return 0.0
return round((income - expenses) / income, 2)Why round(..., 2) specifically — is two decimals the right resolution for a ratio?
For a ratio between 0 and 1, two decimals gives 1% precision. More than enough for a savings rate — a human reader can't tell the difference between 0.25001 and 0.25. Round at the boundary so the caller gets a clean float.
So every division you write has the same three pieces — guard the denominator, do the math, round once at the return.
That's the shape. Clean arithmetic isn't about clever tricks — it's about checking the edges first and doing one operation at a time, in order.
round()TL;DR: guard the denominator → divide → round once at the return.
(income - expenses) / income — the mathround(x, 2) — 2-decimal cleanupif income == 0: return 0.0 — denominator guard| Placement | Effect |
|---|---|
| Inside a chain of math | compounds rounding errors |
| Once at the return | predictable, clean |
Math first, round last. A ratio between 0 and 1 at 2 decimals is plenty of precision for a savings rate.
Write `savings_rate(income, expenses)` that returns `(income - expenses) / income` rounded to 2 decimals. If income is 0, return 0.0.
Tap each step for scaffolded hints.
No blank-editor panic.