Monocurl Essays
Series Download

Fibonacci numbers and thinking recursively

Count the ways to climb a staircase and the Fibonacci numbers appear. Their rule, two identities, Binet's formula and the golden ratio, all proved.

20 min·High school and early college·

AssumesMathematical induction: infinitely many dominoes

Every way to climb 5 stairs when each step goes up 1 stair or 2. Each climb is recorded on the right as a row of tiles, a square for a step of 1 and a wide tile for a step of 2. There are 8.
Monocurl source
let N = 5
let CL = climbs(N)
let X0 = -3.75
let W = 0.56
let Y0 = -1.55
let H = 0.5
let stand = |k| [X0 + (k + 0.5) * W, Y0 + k * H + 0.15, 0]
let hop = |a, b, s| lerp(stand(a), stand(b), s) + [0, (0.3 + 0.12 * (b - a)) * 4 * s * (1 - s), 0]
let STAIRS = block {
    . [X0, Y0 - 0.45, 0]
    for (k in range(0, N + 1)) {
        . [X0 + k * W, Y0 + k * H, 0]
        . [X0 + (k + 1) * W, Y0 + k * H, 0]
    }
    . [X0 + (N + 1) * W, Y0 - 0.45, 0]
}
let row_at = |r| [0.75, 1.3 - r * 0.42, 0]
let Climb = |t| {
    let c = to_int(clamp(0, floor(t), len(CL) - 1))
    let parts = CL[c]
    let m = len(parts)
    let q = clamp(0, (t - c) / 0.8, 1) * m
    var out = []
    var level = 0
    for (j in range(0, m)) {
        let f = clamp(0, q - j, 1)
        let a = level
        let b = level + parts[j]
        if (f > 0.08) {
            out .= Path(map(sample(0, f, to_int(max(2, ceil(f * 14)))), |s| hop(a, b, s)), TILE_COL[parts[j] - 1], 4)
        }
        if (q - j >= 0 and (q - j < 1 or j == m - 1)) {
            out .= Pt(hop(a, b, f), INK, 0.12)
        }
        level = b
    }
    let whole = to_int(floor(q + 0.001))
    out .= map(range(0, c), |r| Strip(row_at(r), CL[r], 0.5, 0.34))
    out .= Strip(row_at(c), take(parts, whole), 0.5, 0.34)
    out .= center{[-2.75, 1.05, 0]} scale{1.6} color{LEAF} Number(c + (whole == m), 0)
    return out
}
mesh stairs = [
    Shape(STAIRS, SLATE, 0.15, 2.5),
    map(range(1, N + 1), |k| center{[X0 + (k + 0.5) * W, Y0 + k * H - 0.25, 0]} Math(to_string(k), 0.72, SLATE)),
    center{[-2.75, 1.65, 0]} Note("ways found", 0.85),
    center{[2.0, 1.85, 0]} Cap("climbs of 5 stairs", 0.8, INK)
]
mesh climb = Climb(t: 0)

slide "climb"
    play Wait(0.5)
    climb.t = 8
    play Lerp(9.5, [&climb], linear)
    play Wait(1.8)

Uses the shared definitions for this lesson's figures.

A staircase has 10 stairs. You climb it by taking either one stair or two stairs with each step, mixing them however you like. In how many different ways can you reach the top? Write down a guess before reading on.

A common guess is a number near 20. The answer is 89, and listing 89 climbs is not how anyone finds it. The way to find it is to notice that the problem contains smaller copies of itself. That habit of mind is called recursive thinking, and the numbers this staircase produces are the best-known example of it.

Small staircases first

With 1 stair there is one way: a single step. With 2 stairs there are two ways, two steps of 1 or one step of 2. I will record a climb by the sizes of its steps, so the climbs of 3 stairs are $1 + 1 + 1$, $1 + 2$ and $2 + 1$. The order matters: $1 + 2$ and $2 + 1$ are different climbs.

All climbs of 1, 2, 3 and 4 stairs, each drawn as a row of tiles: a square is a step of 1 and a wide tile is a step of 2. The counts are 1, 2, 3 and 5.
All climbs of 1, 2, 3 and 4 stairs, each drawn as a row of tiles: a square is a step of 1 and a wide tile is a step of 2. The counts are 1, 2, 3 and 5.
Monocurl source
let LEFT = [-3.45, -2.3, -0.7, 1.45]
mesh table = map(range(1, 5), |n| [
    center{[LEFT[n - 1] + n * 0.25, 1.75, 0]} Cap(str_join([to_string(n), [" stairs", " stair"][n == 1]]), 0.8, INK),
    map(range(0, len(climbs(n))), |r| Strip([LEFT[n - 1], 1.1 - r * 0.55, 0], climbs(n)[r])),
    center{[LEFT[n - 1] + n * 0.25, -1.75, 0]} Cap(str_join([to_string(len(climbs(n))), [" ways", " way"][n == 1]]), 0.85, LEAF)
])

Uses the shared definitions for this lesson's figures.

So the counts begin 1, 2, 3, 5.

Pause and try

Predict the number of climbs of 5 stairs from the pattern 1, 2, 3, 5. Then list them all and see whether you were right.

Show answerHide answer

A tempting prediction is 7, because 2, 3, 5 look like the start of the primes. The list has 8 entries: $1+1+1+1+1$, four climbs with one step of 2 (it can be the first, second, third or fourth step), and three climbs with two steps of 2, namely $1+2+2$, $2+1+2$, $2+2+1$. The animation above finds the same 8.

A pattern read off four numbers is a guess. To know what comes next we need a reason, and the reason will also tell us how to compute the count for 10 stairs without a list.

Sort the climbs by their last step

Write $s_n$ for the number of climbs of $n$ stairs, so $s_1 = 1$, $s_2 = 2$, $s_3 = 3$, $s_4 = 5$, $s_5 = 8$. Take the 8 climbs of 5 stairs and ask of each one how it ended.

  1. All 8 climbs of 5 stairs, each written as its sequence of steps.
  2. Sort them by the last step. Five climbs end with a step of 1 and three end with a step of 2.
  3. Take the last step away. On the left are all 5 climbs of 4 stairs, and on the right all 3 climbs of 3 stairs.
  4. So the count for 5 stairs is the count for 4 plus the count for 3.
The 8 climbs of 5 stairs, sorted by their last step. Removing a last step of 1 leaves a climb of 4 stairs, and removing a last step of 2 leaves a climb of 3 stairs, so 8 = 5 + 3.
Monocurl source
let CL = climbs(5)
let last_of = |i| CL[i][len(CL[i]) - 1]
let U = 0.5
let COLX = [-3.45, 0.55]
let rank = |i| count(range(0, i), |j| last_of(j) == last_of(i))
let start = |i| [COLX[i // 4], 1.25 - (i - 4 * (i // 4)) * 0.8, 0]
let goal = |i| [COLX[last_of(i) - 1], 1.1 - rank(i) * 0.55, 0]
let Rows = |g, d| map(range(0, 8), |i| [
    Strip(lerp(start(i), goal(i), g), take(CL[i], len(CL[i]) - 1), U, 0.4),
    Tile(lerp(start(i), goal(i), g)[0] + (5 - last_of(i)) * U + d * 0.4, lerp(start(i), goal(i), g)[1], last_of(i), U, 0.4, TILE_COL[last_of(i) - 1])
])
mesh rows = Rows(g: 0, d: 0)
mesh heads = []
mesh feet = []
mesh result = []

slide "All 8 climbs of 5 stairs, each written as its sequence of steps."
    play Fade(0.6)

slide "Sort them by the last step. Five climbs end with a step of 1 and three end with a step of 2."
    rows.g = 1
    play Lerp(1.6, [&rows])
    heads = [
        center{[-2.2, 1.75, 0]} Cap("last step is 1", 0.82, AZURE),
        center{[1.8, 1.75, 0]} Cap("last step is 2", 0.82, EMBER)
    ]
    play Fade(0.5, [&heads])

slide "Take the last step away. On the left are all 5 climbs of 4 stairs, and on the right all 3 climbs of 3 stairs."
    rows.d = 1
    play Lerp(1.2, [&rows])
    feet = [
        center{[-2.45, -1.75, 0]} Cap("every climb of 4 stairs", 0.8, INK),
        center{[1.3, -0.55, 0]} Cap("every climb of 3 stairs", 0.8, INK)
    ]
    play Fade(0.5, [&feet])

slide "So the count for 5 stairs is the count for 4 plus the count for 3."
    result = [
        center{[1.9, -1.2, 0]} Math("s_5 = s_4 + s_3", 0.9, LEAF),
        center{[1.9, -1.75, 0]} Math("8 = 5 + 3", 0.9, LEAF)
    ]
    play Fade(0.6, [&result])

Uses the shared definitions for this lesson's figures.

Nothing in the figure depended on the number 5. A climb of $n$ stairs ends with a step of 1 or a step of 2. If it ends with a step of 1, what came before is a climb of $n - 1$ stairs, and every climb of $n - 1$ stairs can be finished this way. If it ends with a step of 2, what came before is a climb of $n - 2$ stairs. The two kinds do not overlap and together they are all the climbs, so

$$ s_n = s_{n-1} + s_{n-2} \qquad (n \ge 3). $$

A rule that gives each term of a sequence from earlier terms is called a recurrence. This one needs two starting values, $s_1 = 1$ and $s_2 = 2$, because it reaches back two terms.

Pause and try

Use the recurrence to find $s_{10}$, the answer to the opening question.

Show answerHide answer

Each term is the sum of the two before it: $1, 2, 3, 5, 8, 13, 21, 34, 55, 89$. So $s_{10} = 89$. Eight additions, starting from $s_1 = 1$ and $s_2 = 2$, replaced a list of 89 climbs.

The Fibonacci numbers

The sequence has a standard form that starts two terms earlier.

The first few are $0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144$. They are named after Leonardo of Pisa, called Fibonacci, who used them in 1202 to count rabbits, and they were known to Indian scholars of poetic meter centuries before that, for exactly our reason: a line of verse made of short and long syllables is a staircase climbed in steps of 1 and 2.

Two base cases are needed because the step for $n = 3$ uses both $n = 1$ and $n = 2$. If induction is new to you, the linked lesson explains why a step that leans on two earlier cases needs two cases to start from.

An identity from cutting a climb in two

Recursive thinking is not limited to the last step. Here is a different way to split a climb, and it produces a formula that would be painful to find by algebra. Take the climbs of 5 stairs again and watch stair 3.

The 8 climbs of 5 stairs, sorted by what happens at stair 3. Six of them land on stair 3, and they are all pairs of a climb of 3 stairs and a climb of 2. Two of them jump over stair 3 with a step of 2.
The 8 climbs of 5 stairs, sorted by what happens at stair 3. Six of them land on stair 3, and they are all pairs of a climb of 3 stairs and a climb of 2. Two of them jump over stair 3 with a step of 2.
Monocurl source
let U = 0.5
let A = climbs(3)
let B = climbs(2)
let A1 = climbs(2)
let B1 = climbs(1)
let Cut = |x, y, col| [
    Seg([x, y + 0.2, 0], [x, y + 0.34, 0], col, 3.5),
    Seg([x, y - 0.34, 0], [x, y - 0.2, 0], col, 3.5)
]
mesh landed = block {
    for (i in range(0, len(A))) {
        for (j in range(0, len(B))) {
            . Strip([-3.6 + j * 2.95, 1.15 - i * 0.5, 0], A[i], U, 0.36)
            . Strip([-3.6 + j * 2.95 + 3 * U + 0.15, 1.15 - i * 0.5, 0], B[j], U, 0.36)
        }
    }
}
mesh jumped = block {
    for (i in range(0, len(A1))) {
        for (j in range(0, len(B1))) {
            . Strip([-3.6 + i * 2.95, -1.0, 0], flatten([A1[i], [2], B1[j]]), U, 0.36)
            . Cut(-3.6 + i * 2.95 + 3 * U, -1.0, ROSE)
        }
    }
}
mesh words = [
    center{[-0.8, 1.75, 0]} Cap("the climb lands on stair 3", 0.8, LEAF),
    center{[3.0, 0.65, 0]} Math(str_join([to_string(len(A)), " \times ", to_string(len(B)), " = ", to_string(len(A) * len(B))]), 0.85, LEAF),
    center{[-0.8, -0.45, 0]} Cap("a step of 2 jumps over stair 3", 0.8, ROSE),
    center{[3.0, -1.0, 0]} Math(str_join([to_string(len(A1)), " \times ", to_string(len(B1)), " = ", to_string(len(A1) * len(B1))]), 0.85, ROSE),
    center{[0, -1.75, 0]} Math("s_5 = s_3 s_2 + s_2 s_1", 0.9, INK)
]

Uses the shared definitions for this lesson's figures.

Check it on a case we know: $s_{10} = s_5 s_5 + s_4 s_4 = 64 + 25 = 89$. No algebra was done in this proof. We counted one set in two ways, and that is often the shortest route to an identity between counting numbers.

An identity from stacking squares

A second identity comes from geometry. Add up the squares of the Fibonacci numbers: $1^2 = 1$, then $1 + 1 = 2$, then $1 + 1 + 4 = 6$, then $15$, then $40$.

Pause and try

The sums of squares are $1, 2, 6, 15, 40, 104$. Factor each one and guess the formula for $F_1^2 + F_2^2 + \dots + F_n^2$.

Show answerHide answer

$1 = 1 \cdot 1$, $2 = 1 \cdot 2$, $6 = 2 \cdot 3$, $15 = 3 \cdot 5$, $40 = 5 \cdot 8$, $104 = 8 \cdot 13$. Each is a product of two neighboring Fibonacci numbers, so the guess is $F_n F_{n+1}$.

Squares with sides 1, 1, 2, 3, 5, 8, 13 fit together into a rectangle. Each new square is attached to the long side of the rectangle so far, so the rectangle with n squares measures F(n) by F(n+1), and its area is the sum of the squares.
Monocurl source
let SIDES = map(range(1, 8), |i| fib(i))
var sq_build = [[0, 0, 1]]
var box = [0, 0, 1, 1]
var boxes_build = [[0, 0, 1, 1]]
for (i in range(1, 7)) {
    let s = SIDES[i]
    let side = i - 1 - 4 * ((i - 1) // 4)
    if (side == 0) {
        sq_build .= [box[0], box[3], s]
        box = [box[0], box[1], box[2], box[3] + s]
    }
    if (side == 1) {
        sq_build .= [box[0] - s, box[1], s]
        box = [box[0] - s, box[1], box[2], box[3]]
    }
    if (side == 2) {
        sq_build .= [box[0], box[1] - s, s]
        box = [box[0], box[1] - s, box[2], box[3]]
    }
    if (side == 3) {
        sq_build .= [box[2], box[1], s]
        box = [box[0], box[1], box[2] + s, box[3]]
    }
    boxes_build .= box
}
let SQ = sq_build
let BOXES = boxes_build
let fit = |b| min(1.3, min(6.6 / (b[2] - b[0]), 2.9 / (b[3] - b[1])))
let mid = |b| [(b[0] + b[2]) / 2, (b[1] + b[3]) / 2, 0]
let Stage = |s| {
    let k = to_int(clamp(0, floor(s + 0.0001), 6))
    let f = clamp(0, s - k, 1)
    let k2 = to_int(min(k + 1, 6))
    let zoom = clamp(0, f / 0.5, 1)
    let show = clamp(0, (f - 0.4) / 0.6, 1)
    let u = lerp(fit(BOXES[k]), fit(BOXES[k2]), zoom)
    let c = lerp(mid(BOXES[k]), mid(BOXES[k2]), zoom)
    var out = []
    for (i in range(0, k2 + 1)) {
        let q = SQ[i]
        let a = [1, show][i > k]
        let col = lerp(PAPER, [AZURE, EMBER][i > k], a)
        let x0 = (q[0] - c[0]) * u
        let y0 = -0.45 + (q[1] - c[1]) * u
        let w = q[2] * u
        if (a > 0.02) {
            out .= Shape([[x0, y0, 0], [x0 + w, y0, 0], [x0 + w, y0 + w, 0], [x0, y0 + w, 0]], col, 0.3 * a, 2.5)
            if (w > 0.5) {
                out .= center{[x0 + w / 2, y0 + w / 2, 0]} Math(to_string(q[2]), 0.85, col)
            }
        }
    }
    return out
}
let Eq = |k, col| center{[0, 1.65, 0]} Math(str_join([
    str_join(map(range(0, k + 1), |i| str_join([to_string(SIDES[i]), "^2"])), " + "),
    " = ", to_string(fib(k + 1)), " \times ", to_string(fib(k + 2))
]), 0.9, col)
mesh spiral = Stage(s: 1)
mesh eq = Eq(1, INK)

slide "stack"
    play Wait(0.8)
    for (k in range(2, 7)) {
        eq = []
        spiral.s = k
        play [Fade(0.3, [&eq]), Lerp(0.9, [&spiral])]
        eq = Eq(k, [INK, LEAF][k == 6])
        play Fade(0.3, [&eq])
        play Wait(0.6)
    }
    play Wait(1.6)

Uses the shared definitions for this lesson's figures.

The induction step is the animation in symbols. A rectangle $F_k$ by $F_{k+1}$ has a long side of length $F_{k+1}$, a square of that side fits against it, and the new rectangle is $F_{k+1}$ by $F_k + F_{k+1}$.

The ratio of neighbors

The rectangles in that animation all look alike. Their proportions are $1 \times 2$, $2 \times 3$, $3 \times 5$, $5 \times 8$, $8 \times 13$, and after the first few the shape hardly changes. So divide each Fibonacci number by the one before it.

The ratio of each Fibonacci number to the one before, plotted for the first 12 ratios. The ratios jump above and below a level near 1.618 and close in on it quickly.
Monocurl source
let fr = Frame(0.5, 12.5, 1, 2.05, [-0.7, -0.15, 0], 5.0, 2.9)
let ratio = |n| fib(n + 1) / fib(n)
let Reveal = |k| {
    let n = to_int(clamp(1, floor(k + 0.001), 12))
    var out = []
    if (n >= 2) {
        out .= Path(map(range(1, n + 1), |i| at(fr, i, ratio(i))), AZURE, 2.5)
    }
    out .= map(range(1, n + 1), |i| Pt(at(fr, i, ratio(i)), AZURE, 0.085))
    out .= Pt(at(fr, n, ratio(n)), EMBER, 0.11)
    out .= center{[2.9, 0.75, 0]} scale{1.15} color{INK} Number(fib(n + 1), 0)
    out .= center{[2.9, 0.15, 0]} scale{1.15} color{INK} Number(fib(n), 0)
    out .= center{[2.9, -0.95, 0]} scale{1.3} color{EMBER} Number(ratio(n), 4)
    return out
}
mesh plot = [
    GridLines(fr, [2, 4, 6, 8, 10, 12], [1.2, 1.4, 1.6, 1.8, 2]),
    Axes(fr, "n", ""),
    XTicks(fr, [2, 4, 6, 8, 10, 12]),
    YTicks(fr, [1, 1.2, 1.4, 1.6, 1.8, 2], SLATE, 1),
    center{[fx(fr, 0.5) + 1.0, fy(fr, 2.05) + 0.5, 0]} Math("F_{n+1} / F_n", 0.8, SLATE),
    Seg(at(fr, 0.5, PHI), at(fr, 12.5, PHI), LEAF, 2.5),
    center{[fx(fr, 10.3), fy(fr, PHI) + 0.3, 0]} Math("\varphi \approx 1.618", 0.8, LEAF)
]
mesh panel = [
    center{[2.9, 1.35, 0]} Note("two neighbors", 0.76),
    Seg([2.45, 0.45, 0], [3.35, 0.45, 0], INK, 2.5),
    center{[2.9, -0.45, 0]} Note("their ratio", 0.76)
]
mesh reveal = Reveal(k: 1)

slide "ratios"
    play Wait(0.8)
    reveal.k = 12
    play Lerp(8, [&reveal], linear)
    play Wait(2)

Uses the shared definitions for this lesson's figures.

The ratios are $1,\ 2,\ 1.5,\ 1.667,\ 1.6,\ 1.625,\ 1.6154,\ 1.6190,\ 1.6176,\ 1.6182$. They alternate, too high then too low, and the swings shrink fast. What number are they closing in on?

There is a quick argument. Divide the recurrence $F_{n+1} = F_n + F_{n-1}$ by $F_n$:

$$ \frac{F_{n+1}}{F_n} = 1 + \frac{F_{n-1}}{F_n}. $$

If the ratios settle at some number $x$, then the left side is close to $x$ and the fraction on the right is close to $1/x$, so $x = 1 + 1/x$, that is, $x^2 = x + 1$. The quadratic formula, which comes from completing the square, gives $x = \frac{1 \pm \sqrt 5}{2}$, and the ratios are positive, so $x$ would be $\frac{1 + \sqrt 5}{2} = 1.6180\ldots$

You might object that the argument began with “if”. It shows that there is only one possible limit, and it does not show that the ratios have a limit at all. The objection is right, and a sequence can easily obey a tidy equation in the limit without having one. To close the gap we will find an exact formula for $F_n$.

A formula for the $n$th Fibonacci number

The ratios suggest that for large $n$ each Fibonacci number is about 1.618 times the one before, which is how a geometric sequence $1, x, x^2, x^3, \dots$ behaves. So ask a cleaner question first.

Pause and try

For which numbers $x$ does the geometric sequence $x^n$ obey the Fibonacci rule, $x^n = x^{n-1} + x^{n-2}$ for all $n \ge 2$?

Show answerHide answer

Divide by $x^{n-2}$ (the case $x = 0$ gives nothing useful): the rule holds exactly when $x^2 = x + 1$. That is the same equation as before, and it has two solutions, $\frac{1 + \sqrt5}{2} \approx 1.618$ and $\frac{1 - \sqrt5}{2} \approx -0.618$.

The equation x^2 = x + 1 solved by a picture. The parabola y = x^2 and the line y = x + 1 cross at two points, whose x values are \varphi \approx 1.618 and \psi \approx -0.618.
The equation $x^2 = x + 1$ solved by a picture. The parabola $y = x^2$ and the line $y = x + 1$ cross at two points, whose $x$ values are $\varphi \approx 1.618$ and $\psi \approx -0.618$.
Monocurl source
let fr = Frame(-1.6, 2.4, -0.6, 4.4, [-0.9, 0, 0], 4.6, 3.7)
mesh plot = [
    GridLines(fr, [-1, 1, 2], [1, 2, 3, 4]),
    Axes(fr, "x", ""),
    XTicks(fr, [-1, 1, 2]),
    YTicks(fr, [2, 3, 4])
]
mesh drops = [
    Seg(at(fr, PHI, 0), at(fr, PHI, PHI ^ 2), LEAF, 2),
    Seg(at(fr, PSI, 0), at(fr, PSI, PSI ^ 2), LEAF, 2)
]
mesh curves = [
    Graph(fr, |x| x * x, -1.6, 2.09, AZURE),
    Graph(fr, |x| x + 1, -1.6, 2.4, EMBER),
    center{at(fr, -1.0, 3.7)} Math("y = x^2", 0.85, AZURE),
    center{at(fr, 2.17, 0.9)} Math("y = x + 1", 0.85, EMBER)
]
mesh roots = [
    Pt(at(fr, PHI, PHI ^ 2), LEAF, 0.1),
    Pt(at(fr, PSI, PSI ^ 2), LEAF, 0.1),
    center{[fx(fr, PHI), fy(fr, 0) - 0.33, 0]} Math("\varphi", 0.9, LEAF),
    center{[fx(fr, PSI), fy(fr, 0) - 0.33, 0]} Math("\psi", 0.9, LEAF)
]
mesh panel = [
    center{[2.75, 1.45, 0]} Math("x^2 = x + 1", 0.9, INK),
    center{[2.75, 0.55, 0]} Math("\varphi = \frac{1 + \sqrt{5}}{2}", 0.85, LEAF),
    center{[2.75, -0.1, 0]} Math(str_join(["\approx ", to_string(PHI, 3)]), 0.85, LEAF),
    center{[2.75, -0.95, 0]} Math("\psi = \frac{1 - \sqrt{5}}{2}", 0.85, LEAF),
    center{[2.75, -1.6, 0]} Math(str_join(["\approx ", to_string(PSI, 3)]), 0.85, LEAF)
]

Uses the shared definitions for this lesson's figures.

Call the two solutions $\varphi = \frac{1 + \sqrt5}{2}$, the golden ratio, and $\psi = \frac{1 - \sqrt5}{2}$. Three facts about them will be used: $\varphi + \psi = 1$, $\varphi - \psi = \sqrt 5$, and each satisfies $x^2 = x + 1$.

Neither $\varphi^n$ nor $\psi^n$ is the Fibonacci sequence, since they start $1, \varphi$ and $1, \psi$ instead of $0, 1$. But the Fibonacci rule only adds, so if two sequences obey it, then so does any combination $a\varphi^n + b\psi^n$ with fixed numbers $a$ and $b$. We have two numbers to choose and two starting values to match. At $n = 0$ we need $a + b = 0$, and at $n = 1$ we need $a\varphi + b\psi = 1$. The first gives $b = -a$, and then the second reads $a(\varphi - \psi) = 1$, so $a = 1/\sqrt5$.

It is strange to see $\sqrt 5$ in a formula for whole numbers. The irrational parts cancel every time, and the picture below shows how little the second term contributes.

Left: the Fibonacci numbers (dots) lie almost exactly on the curve \varphi^n / \sqrt5. Right: the gap between each Fibonacci number and the curve. The gap changes sign at every step, shrinks, and never reaches one half.
Left: the Fibonacci numbers (dots) lie almost exactly on the curve $\varphi^n / \sqrt5$. Right: the gap between each Fibonacci number and the curve. The gap changes sign at every step, shrinks, and never reaches one half.
Monocurl source
let fl = Frame(0, 9.6, 0, 37, [-1.75, -0.15, 0], 3.0, 2.9)
let fe = Frame(-0.5, 9.6, -0.55, 0.55, [2.0, -0.15, 0], 2.5, 2.9)
let gap = |n| fib(n) - PHI ^ n / sqrt(5)
mesh left = [
    GridLines(fl, [2, 4, 6, 8], [10, 20, 30]),
    Axes(fl),
    XTicks(fl, [2, 4, 6, 8]),
    center{[fx(fl, 9.6) + 0.1, fy(fl, 0) - 0.33, 0]} Math("n", 0.8, SLATE),
    YTicks(fl, [10, 20, 30]),
    Graph(fl, |x| PHI ^ x / sqrt(5), 0, 9.15, EMBER, 3.5),
    map(range(0, 10), |n| Pt(at(fl, n, fib(n)), AZURE, 0.085)),
    map(range(6, 10), |n| center{[fx(fl, n) - 0.3, fy(fl, fib(n)) + 0.12, 0]} Math(to_string(fib(n)), 0.74, AZURE)),
    center{[-1.75, 1.85, 0]} Cap("Fibonacci numbers and the curve", 0.74, INK)
]
mesh right = [
    Seg(at(fe, -0.5, 0.5), at(fe, 9.6, 0.5), LEAF, 2),
    Seg(at(fe, -0.5, -0.5), at(fe, 9.6, -0.5), LEAF, 2),
    Axes(fe),
    XTicks(fe, [1, 3, 5, 7, 9]),
    center{[fx(fe, 9.6) + 0.22, fy(fe, 0) - 0.33, 0]} Math("n", 0.8, SLATE),
    YTicks(fe, [-0.5, 0.5], SLATE, 1),
    map(range(0, 10), |n| [Seg(at(fe, n, 0), at(fe, n, gap(n)), PLUM, 6), Pt(at(fe, n, gap(n)), PLUM, 0.075)]),
    center{[2.0, 1.85, 0]} Cap("the gap", 0.74, INK)
]

Uses the shared definitions for this lesson's figures.

Since $|\psi| < 1$, the term $\psi^n / \sqrt 5$ has size at most $\frac{1}{\sqrt5} < \frac12$ for every $n \ge 0$. So $F_n$ is the whole number nearest to $\varphi^n / \sqrt 5$, and for large $n$ the Fibonacci numbers are, to a tiny error, a geometric sequence with ratio $\varphi$.

Why the ratio converges to the golden ratio

Now the “if” can be removed.

The exact equation explains everything in the ratio plot. Because $\psi$ is negative, $\psi^n$ changes sign at every step, so the ratios land alternately above and below $\varphi$. And the error at step $n$ is $|\psi|^n / F_n$, where the top shrinks and the bottom grows: at $n = 10$ it is already $0.0081 / 55 \approx 0.00015$.

The theorem has a hypothesis hiding in it: the starting values. The sequence $1, \psi, \psi^2, \psi^3, \dots$ obeys the same recurrence, and the ratio of its neighbors is $\psi$ at every step, never near $\varphi$. Problem 8 finds exactly which starting values lead to $\varphi$.

Worked examples

Common mistakes

Stepping back

The staircase looked like a problem about listing, and the list was hopeless by 10 stairs. What worked was asking how a climb ends, because the answer exposed two smaller staircases inside the big one. The same question, asked of tilings, bit strings or rectangles, turns many counting problems into a recurrence. Once there is a recurrence, small cases supply the starting values, induction proves what the pattern suggests, and geometric sequences that satisfy the rule lead to an exact formula.

The two numbers $\varphi$ and $\psi$ return in linear algebra, where the step from the pair $(F_{n-1}, F_n)$ to the pair $(F_n, F_{n+1})$ is a matrix and $\varphi$, $\psi$ are its eigenvalues.

Check yourself

A sequence obeys $G_n = G_{n-1} + G_{n-2}$ for $n \ge 3$, with $G_1 = 1$ and $G_2 = 3$. What is $G_5$?

Problems

Problems 1 to 3 repeat the lesson’s moves. Problems 4 to 6 ask you to set up or prove something new. Problems 7 and 8 go further.

Problem 1

Compute $F_{15}$. In how many ways can a staircase of 14 stairs be climbed with steps of 1 and 2?

Show solutionHide solution

Continue the list: $F_{12} = 144$, $F_{13} = 233$, $F_{14} = 377$, $F_{15} = 610$. By the theorem $s_{14} = F_{15} = 610$.

Problem 2

Now each step may go up 1, 2 or 3 stairs. Find a recurrence for the number $t_n$ of climbs of $n$ stairs, and compute $t_7$.

Show solutionHide solution

Sort the climbs by the last step, which is 1, 2 or 3. Removing it leaves a climb of $n - 1$, $n - 2$ or $n - 3$ stairs, and each such climb arises exactly once, so $t_n = t_{n-1} + t_{n-2} + t_{n-3}$ for $n \ge 4$. Three starting values are needed: $t_1 = 1$, $t_2 = 2$ (as before) and $t_3 = 4$ (the climbs $1+1+1$, $1+2$, $2+1$, $3$). Then $t_4 = 7$, $t_5 = 13$, $t_6 = 24$, $t_7 = 44$.

Problem 3

Prove by induction that $F_1 + F_2 + \dots + F_n = F_{n+2} - 1$ for every $n \ge 1$.

Show solutionHide solution

Base case. $F_1 = 1$ and $F_3 - 1 = 2 - 1 = 1$. Step. Assume $F_1 + \dots + F_k = F_{k+2} - 1$. Adding $F_{k+1}$ to both sides gives $F_1 + \dots + F_{k+1} = F_{k+2} + F_{k+1} - 1 = F_{k+3} - 1$, by the recurrence. That is the statement for $k + 1$. Check: $1 + 1 + 2 + 3 + 5 = 12 = 13 - 1$.

Problem 4

A $2 \times n$ board is to be covered by dominoes, each $1 \times 2$ or $2 \times 1$, with no overlaps. Show that the number of ways is $F_{n+1}$.

Show solutionHide solution

Let $d_n$ be the number of tilings and look at the right-hand end of the board. The last column is covered either by one vertical domino, or by the ends of two horizontal dominoes, which then cover the last two columns completely. (One horizontal domino in the top row of the last column forces another below it, because the cell beneath cannot be covered by a vertical domino.) Removing the vertical domino leaves a tiling of a $2 \times (n-1)$ board, and removing the horizontal pair leaves a tiling of a $2 \times (n-2)$ board, and each smaller tiling arises exactly once. So $d_n = d_{n-1} + d_{n-2}$ for $n \ge 3$. Also $d_1 = 1$ and $d_2 = 2$ (two vertical or two horizontal). These are the recurrence and starting values of $s_n$, so $d_n = s_n = F_{n+1}$.

Problem 5

Use the cutting identity to show that $F_{2n} = F_n\,(F_{n+1} + F_{n-1})$ for $n \ge 1$. Deduce that $F_n$ divides $F_{2n}$, and compute $F_{20}$ from $F_9 = 34$, $F_{10} = 55$, $F_{11} = 89$.

Show solutionHide solution

In $F_{m+n+1} = F_{m+1}F_{n+1} + F_m F_n$ replace $m$ by $n - 1$ (allowed for $n \ge 2$, since then $n - 1 \ge 1$): $F_{2n} = F_n F_{n+1} + F_{n-1} F_n = F_n\,(F_{n+1} + F_{n-1})$. For $n = 1$ check directly: $F_2 = 1 = F_1 (F_2 + F_0)$. The second factor is a whole number, so $F_n$ divides $F_{2n}$. With $n = 10$: $F_{20} = 55 \times (89 + 34) = 55 \times 123 = 6765$.

Problem 6

The Lucas numbers obey the Fibonacci recurrence with $L_0 = 2$ and $L_1 = 1$. List them up to $L_6$, and use the method that led to Binet’s formula to find a formula for $L_n$. Check it at $n = 2$.

Show solutionHide solution

$2, 1, 3, 4, 7, 11, 18$. Try $L_n = a\varphi^n + b\psi^n$, which obeys the recurrence for any $a$ and $b$. Matching $n = 0$ gives $a + b = 2$, and matching $n = 1$ gives $a\varphi + b\psi = 1$. Since $\varphi + \psi = 1$, the choice $a = b = 1$ satisfies both. So $L_n = \varphi^n + \psi^n$: both sides obey the recurrence and agree at $n = 0$ and $n = 1$, hence agree for all $n$ by strong induction, exactly as in the proof of Binet’s formula. Check at $n = 2$: $\varphi^2 + \psi^2 = (\varphi + 1) + (\psi + 1) = 1 + 2 = 3 = L_2$.

Problem 7

Prove Cassini’s identity: $F_{n+1}F_{n-1} - F_n^2 = (-1)^n$ for every $n \ge 1$. Then explain the old puzzle in which an $8 \times 8$ square is cut into four pieces that seem to reassemble into a $5 \times 13$ rectangle.

Show solutionHide solution

Base case. For $n = 1$: $F_2 F_0 - F_1^2 = 0 - 1 = -1 = (-1)^1$. Step. Assume $F_{k+1}F_{k-1} - F_k^2 = (-1)^k$. Then

$$ F_{k+2}F_k - F_{k+1}^2 = (F_{k+1} + F_k)F_k - F_{k+1}^2 = F_k^2 - F_{k+1}(F_{k+1} - F_k) = F_k^2 - F_{k+1}F_{k-1} = -(-1)^k = (-1)^{k+1}. $$

For the puzzle take $n = 6$: $F_7 F_5 - F_6^2 = 13 \times 5 - 8^2 = 65 - 64 = 1$. The square has area 64 and the rectangle 65, so the pieces cannot fill the rectangle. They leave a gap of total area 1, and it is hard to see because it is a very thin sliver stretched along the rectangle’s diagonal.

Problem 8

A sequence obeys $G_n = G_{n-1} + G_{n-2}$ for $n \ge 2$, with starting values $G_0$ and $G_1$ that are not both zero. (a) Show that $G_n = A\varphi^n + B\psi^n$ where $A = \dfrac{G_1 - \psi G_0}{\sqrt 5}$ and $B = \dfrac{\varphi G_0 - G_1}{\sqrt5}$. (b) Show that $G_{n+1}/G_n \to \varphi$ if $A \ne 0$, and describe what happens if $A = 0$. (c) Why does every such sequence of whole numbers have ratios converging to $\varphi$?

Show solutionHide solution

(a) The sequence $A\varphi^n + B\psi^n$ obeys the recurrence, so by strong induction it is enough to check $n = 0$ and $n = 1$. At $n = 0$: $A + B = \frac{G_1 - \psi G_0 + \varphi G_0 - G_1}{\sqrt5} = \frac{(\varphi - \psi)G_0}{\sqrt5} = G_0$. At $n = 1$: $A\varphi + B\psi = \frac{\varphi G_1 - \varphi\psi G_0 + \varphi\psi G_0 - \psi G_1}{\sqrt 5} = \frac{(\varphi - \psi)G_1}{\sqrt5} = G_1$.

(b) Write $r = \psi/\varphi$, so $|r| \approx 0.382 < 1$. If $A \ne 0$, divide top and bottom by $\varphi^n$:

$$ \frac{G_{n+1}}{G_n} = \frac{A\varphi + B\psi\, r^n}{A + B r^n}. $$

As $n$ grows, $r^n \to 0$, so the top approaches $A\varphi$ and the bottom approaches $A \ne 0$, and the ratio approaches $\varphi$. If $A = 0$ then $B \ne 0$ and $G_n = B\psi^n$, whose ratio is $\psi$ for every $n$.

(c) $A = 0$ means $G_1 = \psi G_0$. If $G_0 = 0$ this forces $G_1 = 0$, which is excluded. If $G_0 \ne 0$ it says $\psi = G_1/G_0$, a ratio of whole numbers, but $\psi = \frac{1 - \sqrt5}{2}$ is irrational. So $A \ne 0$ for whole-number starting values, and part (b) applies.

Shared definitions used by this lesson's figures
# house kit: prepended to every essay figure after the std imports

# palette. AZURE and EMBER are the two actors, LEAF marks an answer, ROSE a problem
let PAPER = [1, 1, 1, 1]
let INK = [0.08, 0.09, 0.11, 1]
let SLATE = [0.40, 0.44, 0.50, 1]
let MIST = [0.85, 0.86, 0.88, 1]
let AZURE = [0.13, 0.42, 0.68, 1]
let EMBER = [0.89, 0.42, 0.12, 1]
let LEAF = [0.13, 0.55, 0.36, 1]
let ROSE = [0.78, 0.22, 0.24, 1]
let PLUM = [0.47, 0.30, 0.66, 1]
let GOLD = [0.85, 0.62, 0.08, 1]

background = PAPER

# an opaque pastel of col; use for fills so overlaps do not darken
let tint = |col, amount = 0.18| [
    1 - (1 - col[0]) * amount,
    1 - (1 - col[1]) * amount,
    1 - (1 - col[2]) * amount,
    1
]

# text: Cap for labels, Note for quiet labels, Math for typeset maths
let Cap = |txt, size = 0.75, col = INK| color{col} Text(txt, size, "Charter")
let Note = |txt, size = 0.65| color{SLATE} Text(txt, size, "Charter")
let Math = |tex, size = 0.9, col = INK| color{col} Tex(tex, size)

# a paper rectangle to sit behind text that crosses lines
let Plate = |pos, size| center{pos} fill{PAPER} stroke{alpha{0} PAPER, 0} Rect(size)

# shapes with fill and stroke both set, so no stray black appears
let Pt = |pos, col = INK, r = 0.075| center{pos} fill{col} stroke{col, 1} Circle(r, 48)
let Ring = |pos, col = INK, r = 0.1, w = 3| center{pos} fill{PAPER} stroke{col, w} Circle(r, 48)
let Seg = |a, b, col = INK, w = 3| stroke{col, w} Line(a, b)
let Path = |pts, col = INK, w = 3| stroke{col, w} Polyline(pts)
let Region = |pts, col| fill{col} stroke{alpha{0} col, 0} Polygon(pts)
let Outline = |pts, col = INK, w = 3| fill{alpha{0} PAPER} stroke{col, w} Polygon(pts)
let Shape = |pts, col, amount = 0.18, w = 3| fill{tint(col, amount)} stroke{col, w} Polygon(pts)
let Disc = |pos, r, col, amount = 0.18, w = 3| center{pos} fill{tint(col, amount)} stroke{col, w} Circle(r, 96)
let Box = |pos, size, col, amount = 0.18, w = 3| center{pos} fill{tint(col, amount)} stroke{col, w} Rect(size)
# a line from a to b ending in a small solid arrowhead
let Tip = |a, b, col = INK, w = 3, head = 0.17| {
    let d = normalize([b[0] - a[0], b[1] - a[1], 0])
    let n = [-d[1], d[0], 0]
    let base = [b[0] - d[0] * head, b[1] - d[1] * head, 0]
    return [
        stroke{col, w} Line(a, base),
        fill{col} stroke{col, 1} Polygon([
            b,
            [base[0] + n[0] * head * 0.42, base[1] + n[1] * head * 0.42, 0],
            [base[0] - n[0] * head * 0.42, base[1] - n[1] * head * 0.42, 0]
        ])
    ]
}

# plots. a frame is [x0, x1, y0, y1, centre, width, height]: a data window and the scene box it fills
let Frame = |x0, x1, y0, y1, c = [0, 0, 0], w = 6.4, h = 3.6| [x0, x1, y0, y1, c, w, h]
let fx = |fr, x| fr[4][0] + (x - (fr[0] + fr[1]) / 2) * fr[5] / (fr[1] - fr[0])
let fy = |fr, y| fr[4][1] + (y - (fr[2] + fr[3]) / 2) * fr[6] / (fr[3] - fr[2])
let at = |fr, x, y| [fx(fr, x), fy(fr, y), 0]

# axes through the data origin (or the nearest edge of the window), with optional names
let Axes = |fr, x_name = "", y_name = "", col = SLATE| {
    let ox = clamp(fr[0], 0, fr[1])
    let oy = clamp(fr[2], 0, fr[3])
    var parts = [
        Tip(at(fr, fr[0], oy), [fx(fr, fr[1]) + 0.25, fy(fr, oy), 0], col, 2.5, 0.15),
        Tip(at(fr, ox, fr[2]), [fx(fr, ox), fy(fr, fr[3]) + 0.25, 0], col, 2.5, 0.15)
    ]
    if (x_name != "") {
        parts .= center{[fx(fr, fr[1]) + 0.5, fy(fr, oy), 0]} Math(x_name, 0.8, col)
    }
    if (y_name != "") {
        parts .= center{[fx(fr, ox), fy(fr, fr[3]) + 0.5, 0]} Math(y_name, 0.8, col)
    }
    return parts
}

# tick marks with numbers at the listed data values
let XTicks = |fr, xs, col = SLATE, places = 0| block {
    let oy = fy(fr, clamp(fr[2], 0, fr[3]))
    for (x in xs) {
        . Seg([fx(fr, x), oy - 0.07, 0], [fx(fr, x), oy + 0.07, 0], col, 2)
        . center{[fx(fr, x), oy - 0.33, 0]} Math(to_string(x, places), 0.72, col)
    }
}
let YTicks = |fr, ys, col = SLATE, places = 0| block {
    let ox = fx(fr, clamp(fr[0], 0, fr[1]))
    for (y in ys) {
        . Seg([ox - 0.07, fy(fr, y), 0], [ox + 0.07, fy(fr, y), 0], col, 2)
        . center{[ox - 0.36, fy(fr, y), 0]} Math(to_string(y, places), 0.72, col)
    }
}

# faint grid lines at the listed data values
let GridLines = |fr, xs, ys, col = MIST| block {
    for (x in xs) {
        . Seg(at(fr, x, fr[2]), at(fr, x, fr[3]), col, 1.5)
    }
    for (y in ys) {
        . Seg(at(fr, fr[0], y), at(fr, fr[1], y), col, 1.5)
    }
}

# the graph of f over [a, b], drawn in the frame. values are clamped to the window
let Graph = |fr, f, a, b, col = AZURE, w = 4, n = 160|
    stroke{col, w} Polyline(map(sample(a, b, n), |x| at(fr, x, clamp(fr[2], f(x), fr[3]))))

# the region between the graph of f and the x axis over [a, b]
let AreaUnder = |fr, f, a, b, col = AZURE, amount = 0.2, n = 80| {
    var pts = [at(fr, a, 0)]
    for (x in sample(a, b, n)) {
        pts .= at(fr, x, clamp(fr[2], f(x), fr[3]))
    }
    pts .= at(fr, b, 0)
    return fill{tint(col, amount)} stroke{alpha{0} col, 0} Polygon(pts)
}

let PHI = (1 + sqrt(5)) / 2
let PSI = (1 - sqrt(5)) / 2
let fib = |n| {
    var a = 0
    var b = 1
    for (i in range(0, n)) {
        let c = a + b
        a = b
        b = c
    }
    return a
}
# every way to write n as a sum of 1s and 2s, in dictionary order
let climbs = |n| {
    var done = []
    var work = [[]]
    while (len(work) > 0) {
        let p = work[len(work) - 1]
        work = take(work, len(work) - 1)
        let total = sum(p)
        if (total == n) {
            done .= p
        } else {
            if (total + 2 <= n) {
                let two = p .. 2
                work .= two
            }
            let one = p .. 1
            work .= one
        }
    }
    return done
}
let TILE_COL = [AZURE, EMBER]
# one step drawn as a tile p stairs wide, with its left edge at x
let Tile = |x, y, p, u, h, col| [
    Box([x + p * u / 2, y, 0], [p * u - 0.06, h], col, 0.3, 2.5),
    center{[x + p * u / 2, y, 0]} Math(to_string(p), 0.72, col)
]
# a climb drawn as a row of tiles starting at org
let Strip = |org, parts, u = 0.5, h = 0.4| {
    var out = []
    var x = org[0]
    for (p in parts) {
        out .= Tile(x, org[1], p, u, h, TILE_COL[p - 1])
        x = x + p * u
    }
    return out
}