Skip to content
The Lumenary
Grades 6–8Ages 11–14 55 min

Ratios, rates and proportional reasoning

“Three times as much”, not “three more” — how scaling works, how to spot a proportional relationship, and why percentage changes multiply.

Formally verified · 18 LeanComputationally tested · 2 PythonAI-drafted · awaiting human reviewMathematically reviewed: Awaiting human review

Your guides: Chloe, Margaret, Gideon

MotivationH

Better buys and stronger lemonade

At a market in Lima, one stall sells 3 kg of rice for 12 soles; the next sells 5 kg for 19 soles. Which is the better buy? The second costs more in total — but you also get more rice.

Two jugs of lemonade are mixed from concentrate and water:

  • jug A: 2 cups of concentrate and 3 cups of water;
  • jug B: 3 cups of concentrate and 5 cups of water.

Which tastes more lemony? Jug B has one more cup of concentrate — and also two more cups of water.

And a shopkeeper raises a price by 10%, then a week later lowers it by 10%. Is it back where it started?

Each question compares quantities multiplicatively (“how many times as much?”) rather than additively (“how much more?”). That shift is what this lesson is about.

IntuitionH

Thinking in times, not in more

Here is a classic puzzle used by researchers studying how children reason. Mr Short is 4 buttons tall. Measured with paper clips, he is 6 clips tall. His friend Mr Tall is 6 buttons tall. How many paper clips tall is Mr Tall?

A tempting answer is 88: “Mr Tall is 2 buttons more, so 2 clips more.” But a button and a clip are different sizes. Since 4 buttons match 6 clips, 1 button matches 64=1.5\tfrac64 = 1.5 clips, so 6 buttons match 6×1.5=96 \times 1.5 = 9 clips. The two heights are in the same ratio whatever we measure them with: 4:64 : 6 buttons-to-clips, and 6:96 : 9.

The tools of this lesson keep the multiplicative structure visible:

  • a ratio table, whose rows are all scaled copies of each other;
  • a double number line, with one quantity above and one below, matched at every point;
  • the unit rate: how much of one quantity goes with one unit of the other.
buttons24681
clips369121.5
DefinitionsH

Definitions

Definition— ratio

A ratio a:ba : b (“aa to bb”) compares two quantities aa and bb. Two ratios a:ba : b and c:dc : d of positive quantities are equivalent if one is a scaled copy of the other: c=kac = ka and d=kbd = kb for one number k>0k > 0.

So 2:32 : 3, 4:64 : 6 and 10:1510 : 15 are equivalent (scale factors 22 and 55), but 2:32 : 3 and 3:43 : 4 are not. A ratio can compare part to part (2 cups of concentrate to 3 cups of water) or part to whole (2 cups of concentrate in 5 cups of lemonade, so 25\tfrac25 of the jug is concentrate). A probability with equally likely outcomes is a part-to-whole ratio too: favourable outcomes to all outcomes.

Definition— rate and unit rate

A rate is a ratio of two quantities measured in different units, such as 360 km in 4 hours. The unit rate is the amount of the first quantity per one unit of the second: 360÷4=90360 \div 4 = 90 km per hour.

Definition— proportional relationship

A quantity yy is proportional to a quantity xx if there is a fixed number kk, the constant of proportionality, with

y=kxfor every value of x.y = kx \quad \text{for every value of } x.

The constant kk is the unit rate: the value of yy when x=1x = 1.

Definition— percent

Percent means “per hundred”: p%p\% means p100\tfrac{p}{100}, and p%p\% of xx is p100⋅x\tfrac{p}{100} \cdot x.

Worked examplesH

Worked examples

Example— The better buy

Compare unit prices: 12÷3=412 \div 3 = 4 soles per kg, and 19÷5=3.819 \div 5 = 3.8 soles per kg. The 5 kg bag is the better buy. (We could also compare kilograms per sol: 0.250.25 against about 0.2630.263. Either unit rate works, as long as we compare like with like.)

Example— The stronger lemonade

Compare the part-to-whole fractions of concentrate: jug A is 25=0.4\tfrac25 = 0.4 concentrate, jug B is 38=0.375\tfrac38 = 0.375. Jug A is stronger. The ratios 2:32 : 3 and 3:53 : 5 are not equivalent: adding one cup of each is not scaling.

Example— Scaling a recipe

A jollof rice recipe for 4 people uses 3 cups of rice. How much for 10 people? The unit rate is 34\tfrac34 cup per person, so 10×34=7.510 \times \tfrac34 = 7.5 cups. Or scale directly: 1010 people is 104=2.5\tfrac{10}{4} = 2.5 times as many, so 2.5×3=7.52.5 \times 3 = 7.5 cups.

Example— A proportional relationship in the real world

Since 1999 the West and Central African CFA francs have had a fixed exchange rate with the euro: 11 euro =655.957= 655.957 CFA francs. So the number of francs yy is proportional to the number of euros xx: y=655.957 xy = 655.957\,x. For example, 2020 euros is 13 119.1413\,119.14 francs.

Example— Straight lines that are not proportional

  • A taxi charges a start fee of 200 plus 150 per km: fare =150x+200= 150x + 200. Each extra kilometre adds the same amount, so the graph is a straight line — but 11 km costs 350350 and 22 km costs 500500, not 700700. The fare is not proportional to the distance.
  • Amara is 5 and her brother is 8. When Amara is 10, her brother is 13, not 16: their ages differ by a constant, they are not in a constant ratio.

Example— Percentages

  • 15%15\% of 240240 is 15100×240=36\tfrac{15}{100} \times 240 = 36.
  • Increasing 240240 by 15%15\% gives 240+36=276=1.15×240240 + 36 = 276 = 1.15 \times 240.
  • A price after a 20%20\% discount is 240240. The original price PP satisfies 0.8P=2400.8P = 240, so P=300P = 300. (Not 240+20%240 + 20\% of 240=288240 = 288: the discount was 20%20\% of the original price.)
ProofH

Why the methods work

Theorem— Theorem 1 (cross-multiplication)

For positive quantities, a:ba : b is equivalent to c:dc : d exactly when ad=bcad = bc, that is, exactly when ab=cd\tfrac ab = \tfrac cd.

Proof

If c=kac = ka and d=kbd = kb, then ad=a(kb)=b(ka)=bcad = a(kb) = b(ka) = bc. Conversely, suppose ad=bcad = bc. Let k=cak = \tfrac ca, which is positive. Then ka=cka = c, and kb=bca=ada=dkb = \tfrac{bc}{a} = \tfrac{ad}{a} = d. So c:dc : d is a:ba : b scaled by kk.

∎

For the lemonade: 2⋅5=102 \cdot 5 = 10 but 3⋅3=93 \cdot 3 = 9, so 2:32 : 3 and 3:53 : 5 are not equivalent.

Theorem— Theorem 2 (spotting proportionality)

yy is proportional to xx exactly when y=0y = 0 for x=0x = 0 and the ratio yx\tfrac yx is the same for every x≠0x \neq 0. The common ratio is kk.

Proof

If y=kxy = kx, then y=0y = 0 when x=0x = 0, and yx=k\tfrac yx = k whenever x≠0x \neq 0. Conversely, if yx=k\tfrac yx = k for all x≠0x \neq 0, then y=kxy = kx for those xx; and for x=0x = 0 we are told y=0=k⋅0y = 0 = k \cdot 0.

∎

Theorem— Theorem 3 (the graph)

The graph of y=kxy = kx is a straight line through the origin: it contains (0,0)(0, 0), and the slope between any two of its points is kk.

Proof

x=0x = 0 gives y=0y = 0. For two points (x1,kx1)(x_1, kx_1) and (x2,kx2)(x_2, kx_2) with x1≠x2x_1 \neq x_2, the slope is

kx2−kx1x2−x1=k(x2−x1)x2−x1=k.\frac{kx_2 - kx_1}{x_2 - x_1} = \frac{k(x_2 - x_1)}{x_2 - x_1} = k.

A constant slope means the points lie on one straight line.

∎

So a proportional graph is a straight line through the origin — but, as the taxi shows, a straight line that misses the origin is not proportional. In linear relationships you will study all straight lines y=mx+cy = mx + c; the proportional ones are exactly those with c=0c = 0.

Theorem— Theorem 4 (ratio tables)

If y=f(x)y = f(x) is proportional, then for all x1,x2x_1, x_2 and every number cc:

f(x1+x2)=f(x1)+f(x2)andf(cx)=c f(x).f(x_1 + x_2) = f(x_1) + f(x_2) \qquad \text{and} \qquad f(cx) = c\,f(x).

So adding two rows of a ratio table, or multiplying a row by a number, gives another correct row.

Proof

f(x1+x2)=k(x1+x2)=kx1+kx2=f(x1)+f(x2)f(x_1 + x_2) = k(x_1 + x_2) = kx_1 + kx_2 = f(x_1) + f(x_2) by the distributive law, and f(cx)=k(cx)=c(kx)=cf(x)f(cx) = k(cx) = c(kx) = c f(x).

∎

For the taxi, adding rows fails: 11 km (350350) plus 22 km (500500) would predict 850850 for 33 km, but the fare is 650650 — the start fee has been counted twice.

There is a converse for whole numbers. If the price of m+nm + n identical items is always the price of mm items plus the price of nn items, then the price of nn items is nn times the price of one: f(n)=f(1+1+⋯+1)=f(1)+⋯+f(1)=n f(1)f(n) = f(1 + 1 + \cdots + 1) = f(1) + \cdots + f(1) = n\,f(1). “Combining amounts combines the costs” is exactly proportionality.

Theorem— Theorem 5 (percentage changes multiply)

A rise of p%p\% multiplies an amount by 1+p1001 + \tfrac{p}{100}, and a fall of p%p\% multiplies it by 1−p1001 - \tfrac{p}{100}. So successive changes multiply, and their order does not matter. In particular, a rise of p%p\% followed by a fall of p%p\% multiplies the amount by

(1+p100)(1−p100)=1−(p100)2,\left(1 + \tfrac{p}{100}\right)\left(1 - \tfrac{p}{100}\right) = 1 - \left(\tfrac{p}{100}\right)^2,

which is less than 11 whenever p≠0p \neq 0.

Proof

A rise of p%p\% turns xx into x+p100x=(1+p100)xx + \tfrac{p}{100}x = \left(1 + \tfrac{p}{100}\right)x; similarly for a fall. Two changes multiply xx by both factors, and multiplication is commutative, so the order does not matter. Writing r=p100r = \tfrac{p}{100}, (1+r)(1−r)=1−r+r−r2=1−r2(1 + r)(1 - r) = 1 - r + r - r^2 = 1 - r^2. If r≠0r \neq 0 then r2>0r^2 > 0 (a positive times a positive, or a negative times a negative), so 1−r2<11 - r^2 < 1.

∎

For p=10p = 10: the factor is 1.1×0.9=0.991.1 \times 0.9 = 0.99, so the price ends 1%1\% lower. The fall is 10%10\% of a bigger number than the rise was.

Theorem— Theorem 6 (undoing a rise)

A rise of p%p\% (with p≥0p \ge 0) is undone by a fall of 100p100+p%\dfrac{100p}{100 + p}\%.

Proof

(1+p100)(1−p100+p)=100+p100⋅100100+p=1.\left(1 + \tfrac{p}{100}\right)\left(1 - \tfrac{p}{100 + p}\right) = \tfrac{100 + p}{100} \cdot \tfrac{100}{100 + p} = 1.

∎

A 25%25\% rise is undone by a 20%20\% fall; a 100%100\% rise (doubling) by a 50%50\% fall (halving).

Formal mathematicsF

Proportional reasoning in Lean

We use core Lean's exact rational numbers Rat. First, equivalent ratios and cross-multiplication (Theorem 1), with the lemonade as an example. Routine algebra is closed by grind, Lean's built-in prover for the rules of arithmetic.

EquivalentLean 4Formally verified
/-- The ratio `a : b` is *equivalent* to `c : d` if `c : d` is a scaled copy of it:
`c = k · a` and `d = k · b` for one scale factor `k > 0`. -/
def Equivalent (a b c d : Rat) : Prop := ∃ k : Rat, 0 < k ∧ c = k * a ∧ d = k * b
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
equivalent_iff_cross_mulLean 4Proved here from basic factsFormally verified
/-- **Cross-multiplication.** For positive quantities, `a : b` is equivalent to `c : d` exactly
when `a · d = b · c`. One way: `a·(k·b) = b·(k·a)`. The other way: the scale factor is
`k = c / a`, and `a·d = b·c` gives `d = k·b`. (Only `a > 0` and `c > 0` are needed.) -/
theorem equivalent_iff_cross_mul {a b c d : Rat} (ha : 0 < a) (hc : 0 < c) :
    Equivalent a b c d ↔ a * d = b * c := by
  constructor
  · intro ⟨k, _, hck, hdk⟩
    rw [hck, hdk]
    grind
  · intro h
    have ha0 : a ≠ 0 := Rat.ne_of_gt ha
    refine ⟨c / a, ?_, ?_, ?_⟩
    · rw [Rat.lt_div_iff ha]
      simpa using hc
    · grind
    · -- From `a · d = b · c`: `d = (b · c) / a = (c / a) · b`.
      grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
lemonadeLean 4Proved here from basic factsFormally verified
/-- The lemonade puzzle: `2 : 3` (concentrate to water) and `3 : 5` are **not** equivalent,
because `2 · 5 = 10` but `3 · 3 = 9`. Adding one cup of each is not scaling. -/
theorem lemonade : ¬ Equivalent 2 3 3 5 := by
  rw [equivalent_iff_cross_mul (by decide) (by decide)]
  decide +kernel
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor

A proportional relationship is a function f with f x = k * x for one constant k. Then we prove that its graph passes through the origin, that the taxi-style line y=2x+1y = 2x + 1 is not proportional, and Theorem 2.

IsProportionalLean 4Formally verified
/-- A relationship `y = f x` is *proportional* if there is one constant `k` (the constant of
proportionality) with `f x = k · x` for every `x`. -/
def IsProportional (f : Rat → Rat) : Prop := ∃ k : Rat, ∀ x, f x = k * x
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
proportional_zeroLean 4Proved here from basic factsFormally verified
/-- A proportional relationship sends `0` to `0`: `f 0 = k · 0 = 0`. Its graph passes through
the origin. -/
theorem proportional_zero {f : Rat → Rat} (hf : IsProportional f) : f 0 = 0 := by
  obtain ⟨k, hk⟩ := hf
  rw [hk, Rat.mul_zero]
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
affine_not_proportionalLean 4Proved here from basic factsFormally verified
/-- `y = 2x + 1` is a straight line but **not** proportional: it gives `1`, not `0`, at `x = 0`. -/
theorem affine_not_proportional : ¬ IsProportional (fun x => 2 * x + 1) := by
  intro hf
  have h0 := proportional_zero hf
  grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
proportional_iff_ratio_constLean 4Proved here from basic factsFormally verified
/-- **Spotting proportionality in a table.** `f` is proportional exactly when `f 0 = 0` and the
ratio `f x / x` is the same for every `x ≠ 0`. Then `k = f 1`, and `f x / x = f 1` gives
`f x = f 1 · x`. -/
theorem proportional_iff_ratio_const (f : Rat → Rat) :
    IsProportional f ↔ f 0 = 0 ∧ ∀ x, x ≠ 0 → f x / x = f 1 := by
  constructor
  · intro hf
    refine ⟨proportional_zero hf, ?_⟩
    obtain ⟨k, hk⟩ := hf
    intro x hx
    rw [hk x, hk 1]
    grind
  · intro ⟨h0, hratio⟩
    refine ⟨f 1, ?_⟩
    intro x
    by_cases hx : x = 0
    · rw [hx, h0, Rat.mul_zero]
    · have h := hratio x hx
      grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor

Theorem 3 (constant slope) and Theorem 4 (ratio tables), with the whole-number converse proved by induction:

slope_constLean 4Proved here from basic factsFormally verified
/-- **The graph is a straight line through the origin.** Between any two different points of
the graph of `y = k · x`, the slope `(y₂ - y₁)/(x₂ - x₁)` is the same number `k`. -/
theorem slope_const (k x₁ x₂ : Rat) (h : x₁ ≠ x₂) :
    (k * x₂ - k * x₁) / (x₂ - x₁) = k := by
  have hne : x₂ - x₁ ≠ 0 := by
    intro h0
    apply h
    grind
  grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
proportional_addLean 4Proved here from basic factsFormally verified
/-- **Adding rows of a ratio table.** If `f` is proportional, then
`f (x + y) = k·(x + y) = k·x + k·y = f x + f y`. -/
theorem proportional_add {f : Rat → Rat} (hf : IsProportional f) (x y : Rat) :
    f (x + y) = f x + f y := by
  obtain ⟨k, hk⟩ := hf
  rw [hk, hk x, hk y, Rat.mul_add]
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
proportional_scaleLean 4Proved here from basic factsFormally verified
/-- **Scaling a row of a ratio table.** If `f` is proportional, then `f (c · x) = c · f x`. -/
theorem proportional_scale {f : Rat → Rat} (hf : IsProportional f) (c x : Rat) :
    f (c * x) = c * f x := by
  obtain ⟨k, hk⟩ := hf
  rw [hk, hk x]
  grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
additive_natLean 4Proved here from basic factsFormally verified
/-- **Additive implies proportional (for whole numbers).** If the price of `m + n` items is
always the price of `m` items plus the price of `n` items, then the price of `n` items is
`n` times the price of one: `f n = n · f 1`. Proof by induction on `n`. -/
theorem additive_nat (f : Nat → Rat) (hadd : ∀ m n, f (m + n) = f m + f n) :
    ∀ n : Nat, f n = n * f 1 := by
  have h0 : f 0 = 0 := by
    have h := hadd 0 0
    simp at h
    grind
  intro n
  induction n with
  | zero => simp [h0]
  | succ n ih =>
    rw [hadd n 1, ih]
    push_cast
    grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor

Percentages (Theorems 5 and 6):

percentOfLean 4Formally verified
/-- `p` percent of `x` is `p/100` of `x`. -/
def percentOf (p x : Rat) : Rat := p / 100 * x
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
increase_by_percentLean 4Proved here from basic factsFormally verified
/-- Increasing `x` by `p` percent multiplies it by `1 + p/100`:
`x + (p/100)·x = (1 + p/100)·x`. -/
theorem increase_by_percent (p x : Rat) : x + percentOf p x = (1 + p / 100) * x := by
  unfold percentOf
  grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
successive_changes_commuteLean 4Proved here from basic factsFormally verified
/-- Successive percentage changes **multiply**, so their order does not matter: a rise of `p`%
then a rise of `q`% gives the same result as `q`% then `p`%. -/
theorem successive_changes_commute (x p q : Rat) :
    x * (1 + p / 100) * (1 + q / 100) = x * (1 + q / 100) * (1 + p / 100) := by
  grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
ten_up_ten_downLean 4Proved here from basic factsFormally verified
/-- A 10% rise followed by a 10% fall multiplies by `1.1 × 0.9 = 0.99`: you end 1% lower. -/
theorem ten_up_ten_down (x : Rat) : x * (110 / 100) * (90 / 100) = 99 / 100 * x := by
  grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
up_down_factorLean 4Proved here from basic factsFormally verified
/-- Up by a fraction `r`, then down by the same fraction `r`: the overall factor is
`(1 + r)(1 - r) = 1 - r²`. -/
theorem up_down_factor (x r : Rat) : x * (1 + r) * (1 - r) = x * (1 - r * r) := by
  grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
up_down_ltLean 4Proved here from basic factsFormally verified
/-- **Up and down by the same percentage never gets you back.** For a positive amount `x` and
any non-zero change `r`, rising by `r` and then falling by `r` leaves less than `x`:
`x · (1 - r²) = x - x·r² < x`. -/
theorem up_down_lt {x r : Rat} (hx : 0 < x) (hr : r ≠ 0) : x * (1 + r) * (1 - r) < x := by
  rw [up_down_factor]
  have hxr : 0 < x * (r * r) := Rat.mul_pos hx (sq_pos hr)
  grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor
undo_increaseLean 4Proved here from basic factsFormally verified
/-- **Undoing a percentage rise.** A rise of `p`% is undone by a fall of `100p/(100 + p)`%, not
of `p`%: `(1 + p/100) · (1 - p/(100 + p)) = 1`. For `p = 25` the fall is `20`%. -/
theorem undo_increase (p : Rat) (hp : 0 ≤ p) : (1 + p / 100) * (1 - p / (100 + p)) = 1 := by
  have hpos : (0 : Rat) < 100 + p := by
    have : (0 : Rat) < 100 := by decide
    grind
  have hne : (100 : Rat) + p ≠ 0 := Rat.ne_of_gt hpos
  grind
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/RatiosProportions.leanTry it in the Lean web editor

All of these are proved here from the rules of arithmetic for Rat; none simply quotes a library theorem about proportions. In Mathlib, a proportional relationship is a linear map from Q\Q to Q\Q, and every such map is multiplication by a constant.

ComputationC

Classifying tables and multiplying percentages

Proportional, linear or neither? Classifying tables exactlyPythonExact computationComputationally tested
"""Is this table proportional? A classifier that uses exact fractions.

A table of pairs (x, y) comes from a proportional relationship y = kx when
every row with x != 0 has the same ratio y/x and every row with x = 0 has
y = 0. It comes from a straight line when the slope between consecutive rows
is constant. The experiment classifies six real-world tables, then shows the
practical difference: in a proportional table you may add two rows to get a
third, and in a merely linear table you may not.
"""

from fractions import Fraction

TABLES = {
    "millet flour (people, cups)": [(4, 6), (6, 9), (10, 15), (14, 21)],
    "euros to CFA francs": [(1, "655.957"), (20, "13119.14"),
                            (50, "32797.85")],
    "taxi (km, fare)": [(1, 350), (2, 500), (5, 950), (8, 1400)],
    "square (side, perimeter)": [(1, 4), (2, 8), (5, 20)],
    "square (side, area)": [(1, 1), (2, 4), (3, 9), (5, 25)],
    "ages (Amara, brother)": [(5, 8), (10, 13), (20, 23)],
}

def as_pairs(table):
    """Convert table entries to exact Fractions (strings allowed)."""
    return [(Fraction(x), Fraction(y)) for x, y in table]

def constant_of_proportionality(table):
    """Return k if y = k*x for every row, else None."""
    pairs = as_pairs(table)
    ratios = {y / x for x, y in pairs if x != 0}
    if len(ratios) != 1 or any(y != 0 for x, y in pairs if x == 0):
        return None
    return ratios.pop()

def is_linear(table):
    """True if the slopes between consecutive rows (sorted by x) agree."""
    pairs = sorted(as_pairs(table))
    slopes = {(y2 - y1) / (x2 - x1)
              for (x1, y1), (x2, y2) in zip(pairs, pairs[1:])}
    return len(slopes) <= 1

def classify(table):
    """'proportional', 'linear, not proportional' or 'not linear'."""
    if constant_of_proportionality(table) is not None:
        return "proportional"
    if is_linear(table):
        return "linear, not proportional"
    return "not linear"

def add_rows(table, i, j):
    """Add rows i and j of a table: (x_i + x_j, y_i + y_j)."""
    pairs = as_pairs(table)
    return pairs[i][0] + pairs[j][0], pairs[i][1] + pairs[j][1]

def taxi_fare(km):
    """The rule behind the taxi table: 200 to start, 150 per km."""
    return 200 + 150 * Fraction(km)

def main():
    print(f"{'table':<29}{'classification':<26}k = y/x")
    for name, table in TABLES.items():
        k = constant_of_proportionality(table)
        shown = "-" if k is None else (
            str(k) if k.denominator == 1 else f"{float(k):g}")
        print(f"{name:<29}{classify(table):<26}{shown}")
    print()
    print("Adding two rows of a table:")
    x, y = add_rows(TABLES["millet flour (people, cups)"], 0, 1)
    print(f"  flour: 4 people + 6 people -> {x} people need {y} cups;")
    print(f"         the rule y = 3x/2 gives {Fraction(3, 2) * x}: it works.")
    x, y = add_rows(TABLES["taxi (km, fare)"], 0, 1)
    print(f"  taxi:  1 km + 2 km -> adding fares predicts {y} for {x} km,")
    print(f"         but the real fare is {taxi_fare(x)}: the start fee of")
    print("         200 was counted twice.")
    print()
    print("Epistemic status: exact arithmetic on the rows shown. A table only")
    print("samples a relationship: these checks cannot see what happens")
    print("between or beyond the rows. Knowing the rule (y = kx) is what")
    print("makes a relationship proportional.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.
Percentage changes multiply, they do not addPythonExact computationExhaustive finite checkComputationally tested
"""Percentage changes multiply: exact arithmetic with fractions.

A rise of p% multiplies an amount by 1 + p/100 and a fall of p% by
1 - p/100. So "up p%, then down p%" multiplies by (1 + p/100)(1 - p/100),
which is 1 - (p/100)**2: always a little less than 1. This experiment
computes these factors exactly with Python's Fraction type, searches for the
pairs of changes where simply adding the percentages happens to work, finds
the fall that undoes a rise (100p/(100 + p) percent), and compares five 10%
rises with one 50% rise.
"""

from fractions import Fraction

def factor(p):
    """The multiplier for a change of p percent (p may be negative)."""
    return 1 + Fraction(p) / 100

def combined(*changes):
    """The single multiplier equivalent to several percentage changes."""
    total = Fraction(1)
    for p in changes:
        total *= factor(p)
    return total

def as_percent_change(multiplier):
    """Turn a multiplier such as 99/100 into a percentage change (-1)."""
    return (Fraction(multiplier) - 1) * 100

def undo_rise(p):
    """The percentage fall that exactly undoes a rise of p percent."""
    p = Fraction(p)
    if p <= -100:
        raise ValueError("a fall of 100% or more cannot be undone")
    return 100 * p / (100 + p)

def when_adding_works(low, high):
    """Whole-number pairs (p, q) in range where adding the percentages works.

    Adding guesses the multiplier 1 + (p + q)/100; the true multiplier is
    (1 + p/100)(1 + q/100) = 1 + (p + q)/100 + pq/10000. Returns the list of
    pairs where the guess is exactly right, and the number of pairs tried.
    """
    hits = []
    tried = 0
    for p in range(low, high + 1):
        for q in range(low, high + 1):
            tried += 1
            if combined(p, q) == factor(p + q):
                hits.append((p, q))
    return hits, tried

def fmt(x):
    """Show a Fraction as a decimal when it is one, else as a fraction."""
    x = Fraction(x)
    if x.denominator == 1:
        return str(x.numerator)
    if all(p in (2, 5) for p in _prime_factors(x.denominator)):
        return f"{float(x):.6f}".rstrip("0")
    return f"{x} (about {float(x):.2f})"

def _prime_factors(n):
    """Prime factors of n > 0 (with repetition)."""
    out, d = [], 2
    while d * d <= n:
        while n % d == 0:
            out.append(d)
            n //= d
        d += 1
    if n > 1:
        out.append(n)
    return out

def main():
    print("Up p% then down p%: multiplier (1 + p/100)(1 - p/100)")
    print("    p    multiplier    overall change")
    for p in [5, 10, 20, 25, 50, 100]:
        m = combined(p, -p)
        print(f"  {p:3d}%   {fmt(m):>10}    {fmt(as_percent_change(m)):>8}%")
    hits, tried = when_adding_works(-99, 100)
    zero = all(p == 0 or q == 0 for p, q in hits)
    print(f"Adding p% and q% gives the right answer for {len(hits)} of "
          f"{tried} pairs")
    print(f"  (whole p, q in -99..100); every one has p = 0 or q = 0: {zero}")
    print()
    print("The fall that undoes a rise of p%:")
    for p in [10, 25, 50, 100, 300]:
        print(f"  rise {p:3d}%  ->  fall {fmt(undo_rise(p))}%")
    print()
    five = combined(10, 10, 10, 10, 10)
    print(f"Five rises of 10%: multiplier {fmt(five)}, "
          f"a rise of {fmt(as_percent_change(five))}%, not 50%.")
    print()
    print("Epistemic status: exact rational arithmetic. The search is")
    print("exhaustive for 40,000 whole-number pairs only; that adding works")
    print("exactly when pq = 0, for every p and q, follows from the algebra")
    print("(1 + p/100)(1 + q/100) = 1 + (p + q)/100 + pq/10000 in the lesson.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

Adding percentages works only when one of the changes is 0%0\%: the exact algebra (1+p100)(1+q100)=1+p+q100+pq10000\left(1 + \tfrac{p}{100}\right)\left(1 + \tfrac{q}{100}\right) = 1 + \tfrac{p + q}{100} + \tfrac{pq}{10000} shows the extra term pq10000\tfrac{pq}{10000} is zero only then. The search is evidence for 40,000 pairs; the algebra is the proof for all of them.

Explore

Explore: double number lines and lines through the origin

Double number line

3 kg for 12 soles. Find the unit rate, then the price of 5 kg.

kilograms of ricesoles0031262493612481560187214312

3

kilograms of rice

:

12

soles

3 : 12 = 3 : 12 (× 1)

This is the starting ratio.

Unit rates

  • 1 : 4 — For every 1 on the “kilograms of rice” line: 4 on the “soles” line.
  • 0.25 : 1 — For every 1 on the “soles” line: 0.25 on the “kilograms of rice” line.

Equivalent ratios

3 : 12 = 6 : 24 = 9 : 36 = 12 : 48 = …

Divide both by 3 for the simplest form: 1 : 4

×kilograms of ricesoles
000
1/314
1312
2624
3936
41248
51560
61872

Move the marker to 11 kg to read the unit rate, then to 55 kg. The stall that sells 5 kg for 19 soles is cheaper by how much?

Which line is proportional?

Move the sliders and trace along the curves to read off values.

origin
  • y = kx (proportional)
  • y = kx + b
  • y = kx (proportional): y = 1.5
  • y = kx + b: y = 3.5

Change kk: the first line always pivots about the origin. Change bb: the second line slides up and down, and is proportional only when b=0b = 0. Use the trace to check that, on the first line, y÷xy \div x is the same at every point — and on the second line it is not.

Exercises

Exercises

1. Ratios, rates and proportional reasoning

Warm-upHuman

Packets of tea in a shop in Kampala: a 250250 g packet costs 50005000 shillings and a 400400 g packet costs 76007600 shillings. Which is the better buy?

Choose one

2. Ratios, rates and proportional reasoning

Warm-upHuman

A recipe for 66 people uses 44 cups of millet flour. How many cups are needed for 1515 people?

3. Ratios, rates and proportional reasoning

CoreHuman

Mr Short is 44 buttons tall and 66 paper clips tall. Mr Tall is 1010 buttons tall. How many paper clips tall is Mr Tall?

4. Ratios, rates and proportional reasoning

CoreHuman

Which of these relationships are proportional? (Choose all that apply.)

Choose all that apply

5. Ratios, rates and proportional reasoning

CoreHuman

In a proportional relationship, y=7y = 7 when x=2x = 2, and y=17.5y = 17.5 when x=5x = 5. What is yy when x=12x = 12?

6. Ratios, rates and proportional reasoning

CoreHuman

A bicycle costs 200200 dollars. The price rises by 10%10\%, and the next month the new price falls by 10%10\%. What is the final price, in dollars?

7. Ratios, rates and proportional reasoning

CoreHuman

In a sale everything is 20%20\% off. A jacket now costs 240240 reais. What was its price before the sale?

8. Ratios, rates and proportional reasoning

StretchHuman

The population of a town rises by 25%25\%. By what percentage must it then fall to return to its original size?

9. Ratios, rates and proportional reasoning

CoreFormal

Which Lean definition says correctly that ff is proportional (there is one constant kk with f(x)=kxf(x) = kx for every xx)?

Choose one

10. Ratios, rates and proportional reasoning

StretchComputational

Write constant_of_proportionality(table). The table is a list of pairs (x, y). Return the constant kk (as a Fraction) if y=kxy = kx for every row, and None otherwise. Rows with x == 0 must have y == 0, and there must be at least one row with x != 0. Use Fraction so that decimals such as \"0.5\" are exact.

Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.
Common misconceptionsH

Common misconceptions

Misconception

Thinking additively instead of multiplicatively. “Mr Tall is 2 buttons taller, so he is 2 clips taller” gives 88 clips instead of 99. When two quantities are proportional, ask “how many times as much?”, not “how much more?”.

Misconception

“Every straight-line graph is proportional.” y=2x+1y = 2x + 1 is a straight line, but doubling xx does not double yy, and the line misses the origin. Proportional means y=kxy = kx: a straight line through the origin.

Misconception

Adding successive percentage changes. A 10%10\% rise and a 10%10\% fall do not cancel (the result is 1%1\% lower), and five 10%10\% rises make 61.051%61.051\%, not 50%50\%. Percentage changes multiply.

Misconception

Mixing up part-to-part and part-to-whole. In a 2:32 : 3 mix of concentrate to water, concentrate is 25\tfrac25 of the jug, not 23\tfrac23.

Misconception

Confusing percent with percentage points. If an interest rate rises from 4%4\% to 5%5\%, it rises by 11 percentage point — which is a 25%25\% increase in the rate.

ViewpointsH

Other ways of seeing

Geometry— Proportion is similarity

Two figures are similar when one is a scaled copy of the other: all lengths are multiplied by the same factor kk, so corresponding lengths are in the same ratio. A map at scale 1:50 0001 : 50\,000 is similar to the land it shows; the shadows of a pole and of a tree at the same moment form similar triangles, which lets you measure the tree. Thales' intercept theorem says that parallel lines cut two lines through a point in proportional pieces. Similar triangles also explain Theorem 3 geometrically: the points (x,kx)(x, kx) all make similar right triangles with the xx-axis, so they lie on one straight line through the origin. See rigid motions and similarity.

Physics— Laws of proportion — within limits

Many physical laws are proportionalities: distance == speed ×\times time at a steady speed; the stretch of a spring is proportional to the force on it (Hooke's law); the current through many conductors is proportional to the voltage (Ohm's law). A rate carries units — km per hour, newtons per metre — and checking units is a powerful way to catch errors. But such laws are models, true only within limits: stretch a spring too far and Hooke's law fails. Physics discovers proportionalities by measurement; mathematics tells us what follows if they hold.

Algebra— Proportional relationships are linear maps

A proportional relationship f(x)=kxf(x) = kx is exactly a function that respects addition and scaling (Theorem 4): an algebraist calls it a linear map. Composing two of them multiplies the constants: converting euros to CFA francs (k=655.957k = 655.957) and then francs to some other currency (k′k') is again proportional, with constant k′kk'k. That is why chains of unit conversions work. In functions and later in linear algebra this idea grows into matrices.

History & global context

History and global context

  • China. The Nine Chapters on the Mathematical Art (compiled by about the 1st century CE) has a chapter on exchanging one grain for another at fixed rates, and a chapter on distributing goods and taxes in proportion.
  • India. The rule of three (trairāśika) — given three quantities of a proportion, find the fourth — appears in Āryabhaṭa's Āryabhaṭīya (499 CE) and was used throughout Indian mathematics.
  • Greece. Book V of Euclid's Elements (about 300 BCE) develops a general theory of ratio and proportion, traditionally credited to Eudoxus of Cnidus, which even works for lengths that have no common measure.
  • Trade. Through mathematicians writing in Arabic, the rule of three reached Europe; Fibonacci's Liber Abaci (1202) uses it for currency exchange and partnership problems. Percentages grew out of merchants' “per hundred” calculations; the Roman emperor Augustus had already levied a tax of one hundredth on goods sold at auction.
  • Learning. Robert Karplus and colleagues used the “Mr Short and Mr Tall” problem in the 1970s to study how students move from additive to multiplicative reasoning — a transition researchers still study today.
Further reading

Further reading

  • Susan J. Lamon, Teaching Fractions and Ratios for Understanding (1999).
  • Hans Freudenthal, Didactical Phenomenology of Mathematical Structures (1983), chapter “Ratio and proportionality”.
  • Richard Lesh, Thomas Post and Merlyn Behr, “Proportional reasoning”, in J. Hiebert and M. Behr (eds.), Number Concepts and Operations in the Middle Grades (1988).
  • Euclid, The Elements, Book V, in the translation by T. L. Heath (1908).