Monocurl Essays
Series Download

The central limit theorem: why bell curves are everywhere

One die is flat, but the average of 30 dice follows a bell curve. The central limit theorem says when this happens, how fast, and when it fails.

21 min·High school and early college·

AssumesThe normal distribution and the 68-95-99.7 ruleExpected value and the surprising power of adding averages

A simulation. For each of 1, 2, 3, 5, 10 and 30 dice, the dice were rolled 10,000 times and the average recorded. The histogram of the averages starts flat, becomes a triangle, and then a bell that grows narrower and taller. The vertical scale is redrawn at each stage so that the histogram fills the frame, and the numbered ticks record how tall it has become. The curve at the end is the normal density with the same mean and standard deviation.
Monocurl source
let ALL = map(NS, |n| dice_counts(n, TRIALS))
let SDS = map(range(0, 6), |k| avg_sd(ALL[k], NS[k], TRIALS))
let TOPS = [0.3, 0.6, 0.6, 0.9, 1.2, 1.45]
let TICKS = [[0.1, 0.2], [0.2, 0.4], [0.2, 0.4], [0.3, 0.6], [0.4, 0.8], [0.5, 1]]
let fd = Frame(0.5, 6.5, 0, 1.45, [-0.05, 0.1, 0], 6.4, 2.9)
let stage_frame = |k| Frame(0.5, 6.5, 0, TOPS[k], [-0.05, 0.1, 0], 6.4, 2.9)
let Scale = |m| {
    let k = to_int(floor(m + 0.0001))
    return GridLines(stage_frame(k), [], TICKS[k])
}
let Stage = |m| {
    let k = to_int(floor(m + 0.0001))
    return [
        DiceBars(stage_frame(k), ALL[k], NS[k], TRIALS, 0, AZURE),
        YTicks(stage_frame(k), TICKS[k], SLATE, 1),
        center{at(fd, 1.45, 1.13)} scale{1.35} color{INK} Number(NS[k], 0),
        center{at(fd, 5.55, 1.13)} scale{1.35} color{AZURE} Number(SDS[k], 2)
    ]
}
mesh scale_lines = Scale(m: 0)
mesh frame = [
    GridLines(fd, [1, 2, 3, 4, 5, 6], []),
    Axes(fd),
    map([1, 2, 3, 4, 5, 6], |v| center{[fx(fd, v), fy(fd, 0) - 0.3, 0]} Math(to_string(v), 0.74, SLATE)),
    center{[fx(fd, 3.5), fy(fd, 0) - 0.68, 0]} Note("average of the dice", 0.74),
    center{[fx(fd, 0.5) + 1.2, fy(fd, 1.45) + 0.42, 0]} Note("fraction per unit", 0.74),
    center{at(fd, 1.45, 1.33)} Cap("dice averaged", 0.76, INK),
    center{at(fd, 5.55, 1.33)} Cap("sd of the average", 0.76, AZURE)
]
mesh bars = Stage(m: 0)
mesh curve = []

slide "grow"
    play Wait(1)
    bars.m = 5.5
    scale_lines.m = 5.5
    play Lerp(7.5, [&bars, &scale_lines], linear)
    curve = Graph(fd, |x| bell(x, 3.5, DIE_SD / sqrt(30)), 0.5, 6.5, EMBER, 4)
    play Fade(0.8, [&curve])
    play Wait(1.8)

Uses the shared definitions for this lesson's figures.

Roll one fair die many times and draw a histogram of the results. It is flat: each face comes up about a sixth of the time, and there is no hump anywhere. Now roll thirty dice at a time and record their average. The histogram of those averages is a bell curve, and a very good one.

Nothing bell-shaped went into the experiment. The die has no preference for the middle, and the instructions were to add and divide. The normal curve of the last lesson, with its $e^{-z^2/2}$ and its $\sqrt{2\pi}$, appeared from a cube with dots on it.

The same thing happens if the die is replaced by almost any other source of random numbers, and that fact is the central limit theorem. It is the reason heights, measurement errors and exam totals look normal: each is a sum of many small independent contributions. This lesson shows the theorem happening, states it exactly, says why its proof is out of reach here, and then finds a case where it fails.

Two dice, counted by hand

Start with the smallest case that is not flat. Roll two dice and take their average. There are 36 equally likely outcomes, as in the lesson on sample spaces, and the average depends only on the total.

Pause and try

Of the 36 outcomes for two dice, how many give an average of exactly 1? How many give 3.5? Predict the shape of the whole histogram of the average.

Show answerHide answer

An average of 1 needs both dice to show 1, which is one outcome. An average of 3.5 is a total of 7, which happens six ways: (1,6), (2,5), (3,4), (4,3), (5,2), (6,1). The counts rise by one for each step from a total of 2 up to 7 and fall by one from there to 12, so the histogram is a triangle peaked at 3.5.

  1. Two dice have 36 equally likely outcomes, one per cell. Only the corner cell, a pair of 1s, gives an average of 1.
  2. An average of 3.5 is a total of 7. Six cells give it: the long diagonal.
  3. Every diagonal is one value of the average. Their lengths are 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1: a triangle.
The 36 outcomes of two dice, grouped by their average. Each diagonal of the grid is one value of the average, and the diagonals are longest in the middle, which gives a triangular histogram.
Monocurl source
let CELL = 0.5
let GX = -3.3
let GY = -1.5
let cell_pos = |a, b| [GX + (b - 0.5) * CELL, GY + (6.5 - a) * CELL, 0]
let fb = Frame(0.5, 6.5, 0, 6.8, [2.05, -0.1, 0], 3.1, 2.6)
let Diag = |total, col| block {
    for (a in range(1, 7)) {
        if (total - a >= 1 and total - a <= 6) {
            . Box(cell_pos(a, total - a), [CELL - 0.06, CELL - 0.06], col, 0.6, 2.5)
        }
    }
}
let ways = |total| 6 - abs(total - 7)
let Bar = |total, col| Box(at(fb, total / 2, ways(total) / 2), [0.5 * 3.1 / 6 * 0.86, ways(total) * 2.6 / 6.8], col, 0.5, 2)
mesh grid = [
    map(range(1, 7), |a| map(range(1, 7), |b| Box(cell_pos(a, b), [CELL - 0.06, CELL - 0.06], SLATE, 0.1, 1.5))),
    map(range(1, 7), |a| center{[GX - 0.25, GY + (6.5 - a) * CELL, 0]} Math(to_string(a), 0.74, SLATE)),
    map(range(1, 7), |b| center{[GX + (b - 0.5) * CELL, GY + 6 * CELL + 0.25, 0]} Math(to_string(b), 0.74, SLATE))
]
mesh chart = [
    GridLines(fb, [], [2, 4, 6]),
    Axes(fb),
    map([1, 2, 3, 4, 5, 6], |v| center{[fx(fb, v), fy(fb, 0) - 0.3, 0]} Math(to_string(v), 0.74, SLATE)),
    YTicks(fb, [2, 4, 6]),
    center{[fx(fb, 3.5), fy(fb, 0) - 0.68, 0]} Note("average of two dice", 0.74),
    center{[fx(fb, 0.5) + 0.75, fy(fb, 6.8) + 0.42, 0]} Note("outcomes", 0.74)
]
mesh hi = []
mesh bars = []

slide "Two dice have 36 equally likely outcomes, one per cell. Only the corner cell, a pair of 1s, gives an average of 1."
    hi = Diag(2, AZURE)
    bars = [Bar(2, AZURE)]
    play Fade(0.7)

slide "An average of 3.5 is a total of 7. Six cells give it: the long diagonal."
    hi = [Diag(2, AZURE), Diag(7, EMBER)]
    bars .= Bar(7, EMBER)
    play Fade(0.7)

slide "Every diagonal is one value of the average. Their lengths are 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1: a triangle."
    hi = map(range(2, 13), |t| Diag(t, [AZURE, EMBER][t == 7]))
    bars = map(range(2, 13), |t| Bar(t, [AZURE, EMBER][t == 7]))
    play Fade(0.8)

Uses the shared definitions for this lesson's figures.

The reason for the peak is a counting reason. A middling average can be reached in many ways, because a low die can be offset by a high one. An extreme average can be reached in only one way, because every die has to cooperate. With three dice the effect compounds: a total of 3 still needs one specific outcome out of 216, while a total of 10 can be made in 27 ways. The corners of the triangle are rounded off, and with each added die the histogram looks more like a bell, as the figure at the top shows.

Two things happen at once in that figure, and it helps to separate them. The histogram gets narrower, and its shape changes. The narrowing is the law of large numbers: averages of many rolls crowd around 3.5. The amount of narrowing is known exactly. One roll has mean $\mu = 3.5$ and standard deviation $\sigma = \sqrt{35/12} \approx 1.71$, and the average of $n$ independent rolls has mean $\mu$ and standard deviation $\sigma/\sqrt{n}$. (This is proved in the next lesson; here I only use it.) For 30 dice that is $1.71/\sqrt{30} \approx 0.31$, and the simulation’s 10,000 averages had standard deviation 0.31.

Removing the narrowing to see the shape

To study the shape alone, we must stop the histogram from shrinking, and the last lesson supplied the tool: convert to z-scores. Subtract the mean and divide by the standard deviation, using the standard deviation of the average, which is $\sigma/\sqrt n$:

$$ Z_n = \frac{\bar X_n - \mu}{\sigma/\sqrt{n}}. $$

Here $\bar X_n$ is the average of the $n$ rolls. $Z_n$ is called the standardized mean. Whatever $n$ is, $Z_n$ has mean 0 and standard deviation 1, so its histogram can neither drift nor shrink. Only its shape is free to change.

The same simulated dice averages, converted to z-scores. For every number of dice the histogram has mean 0 and standard deviation 1, and as the number grows it fills in the standard normal density (orange). The readout is the share of the 10,000 trials within one standard deviation of the mean, which for a normal distribution is 0.683.
Monocurl source
let ALL = map(NS, |n| dice_counts(n, TRIALS))
let WITHIN = map(range(0, 6), |k| {
    var c = 0
    for (i in range(0, 5 * NS[k] + 1)) {
        if (abs((i + NS[k]) / NS[k] - 3.5) <= DIE_SD / sqrt(NS[k])) {
            c = c + ALL[k][i]
        }
    }
    return c / TRIALS
})
let fz = Frame(-4, 4, 0, 0.5, [0, 0.1, 0], 6.6, 2.9)
let Stage = |m| {
    let k = to_int(floor(m + 0.0001))
    return [
        DiceBars(fz, ALL[k], NS[k], TRIALS, 1, AZURE),
        Graph(fz, phi, -4, 4, EMBER, 4),
        center{at(fz, -3.0, 0.38)} scale{1.35} color{INK} Number(NS[k], 0),
        center{at(fz, 3.0, 0.38)} scale{1.35} color{AZURE} Number(WITHIN[k], 3)
    ]
}
mesh frame = [
    GridLines(fz, [-3, -2, -1, 0, 1, 2, 3], [0.1, 0.2, 0.3, 0.4]),
    Seg(at(fz, -4, 0), at(fz, 4, 0), SLATE, 2.5),
    map([-3, -2, -1, 0, 1, 2, 3], |v| center{[fx(fz, v), fy(fz, 0) - 0.3, 0]} Math(to_string(v), 0.74, SLATE)),
    map([0.1, 0.2, 0.3, 0.4], |v| center{[fx(fz, -4) - 0.32, fy(fz, v), 0]} Math(to_string(v, 1), 0.72, SLATE)),
    center{[fx(fz, 0), fy(fz, 0) - 0.68, 0]} Note("z-score of the average", 0.74),
    center{at(fz, -3.0, 0.45)} Cap("dice averaged", 0.76, INK),
    center{at(fz, 3.0, 0.45)} Cap("within 1 sd", 0.76, AZURE)
]
mesh bars = Stage(m: 0)

slide "fill"
    play Wait(1)
    bars.m = 5.5
    play Lerp(8, [&bars], linear)
    play Wait(1.8)

Uses the shared definitions for this lesson's figures.

On this scale the convergence is plain. One die gives six equal bars, which is nothing like the curve. Two give a triangle. By ten dice the tops of the bars trace the standard normal density closely, and by thirty the fit is hard to fault.

Does it depend on the die?

A die is symmetric, and a bell is symmetric, so perhaps the die was a friendly choice. A harder test is a source that is badly lopsided.

The last lesson ended with one: waiting times for a bus that comes at random moments, with mean 5 minutes and standard deviation 5 minutes (the exponential distribution). Short waits are the most common and long waits trail far to the right. The normal curve was a poor description of those waits.

Pause and try

Suppose you record your wait every morning for 30 mornings and compute the average. Over many such months, what will the histogram of the monthly average look like? Will it keep the long right tail of the single waits? What will its standard deviation be?

Show answerHide answer

Its standard deviation will be $5/\sqrt{30} \approx 0.91$ minutes, by the same $\sigma/\sqrt{n}$ rule. Its shape will be close to a bell centered at 5, as the next figure shows. A little of the right tail survives at $n = 30$, which a later example measures.

A simulation of waiting times with mean 5 minutes, which are far from normal. The histogram shows 5000 averages of 1, 2, 5, 10, 20 and 30 waits. The lopsided shape of a single wait is nearly gone by 30, and the histogram is close to the normal density with mean 5 and standard deviation $5/\sqrt{n}$ (orange).
Monocurl source
let WN = [1, 2, 5, 10, 20, 30]
let WIDTHS = [1, 1, 0.5, 0.5, 0.25, 0.25]
let WT = 5000
let wait_counts = |n, width| {
    let nb = to_int(14 / width)
    var c = map(range(0, nb), |i| 0)
    for (t in range(0, WT)) {
        var s = 0
        for (j in range(0, n)) {
            s = s + wait(t * n + j + 1, 100 + n)
        }
        let b = to_int(floor(s / n / width))
        if (b < nb) {
            c[b] = c[b] + 1
        }
    }
    return c
}
let ALL = map(range(0, 6), |k| wait_counts(WN[k], WIDTHS[k]))
let fw = Frame(0, 14, 0, 0.5, [-0.05, 0.1, 0], 6.4, 2.9)
let Stage = |m| {
    let k = to_int(floor(m + 0.0001))
    let w = WIDTHS[k]
    return [
        map(range(0, len(ALL[k])), |b| Box(at(fw, (b + 0.5) * w, ALL[k][b] / WT / w / 2), [w * 6.4 / 14 * 0.94, max(ALL[k][b] / WT / w, 0.002) * 2.9 / 0.5], AZURE, 0.4, 1.5)),
        stroke{EMBER, 4} Polyline(map(sample(0, 14, 180), |x| at(fw, x, bell(x, 5, 5 / sqrt(WN[k]))))),
        center{at(fw, 11.5, 0.37)} scale{1.35} color{INK} Number(WN[k], 0)
    ]
}
mesh frame = [
    GridLines(fw, [2, 4, 6, 8, 10, 12, 14], [0.1, 0.2, 0.3, 0.4]),
    Axes(fw),
    XTicks(fw, [2, 4, 6, 8, 10, 12, 14]),
    YTicks(fw, [0.1, 0.2, 0.3, 0.4], SLATE, 1),
    center{[fx(fw, 7), fy(fw, 0) - 0.68, 0]} Note("average wait (minutes)", 0.74),
    center{[fx(fw, 0) + 1.35, fy(fw, 0.5) + 0.42, 0]} Note("fraction per minute", 0.74),
    center{at(fw, 11.5, 0.445)} Cap("waits averaged", 0.76, INK)
]
mesh bars = Stage(m: 0)

slide "average"
    play Wait(1.2)
    bars.m = 5.5
    play Lerp(8, [&bars], linear)
    play Wait(1.8)

Uses the shared definitions for this lesson's figures.

The lopsidedness is averaged away. It takes longer than it did for the die: at $n = 5$ the histogram still leans visibly, and at $n = 30$ only a trace is left. But the destination is the same curve, and the die and the bus have nothing in common except that each has a mean and a standard deviation.

The theorem

Each clause corresponds to something in the experiments.

Independent means that knowing some of the values tells you nothing about the others, as with separate rolls. The same distribution means every roll uses the same die. Statisticians abbreviate the pair as i.i.d., independent and identically distributed.

Finite variance is a real restriction. The die and the bus both satisfy it. The last section of this lesson shows what happens without it.

The conclusion is about $Z_n$, the standardized mean. It does not say that $\bar X_n$ itself has a limiting bell shape: $\bar X_n$ piles up at the single point $\mu$. Only after magnifying the deviations $\bar X_n - \mu$ by the factor $\sqrt n/\sigma$ does a fixed shape appear.

The limit is a statement about probabilities of ranges, which are areas under the standard normal density $\varphi$. It says that the area of the histogram of $Z_n$ over any interval approaches the area under $\varphi$ over the same interval. That is what the two videos showed.

Notice what is absent from the right-hand side: any trace of the distribution we started from. Faces of a die, minutes of waiting, anything else with a finite variance, all lead to the same $\varphi$.

What we can prove, and what we cannot

Part of the statement is within reach. The claim that $Z_n$ has mean 0 and standard deviation 1 for every $n$ follows from two facts about expected values and variances. The first is linearity, $E[aX + b] = aE[X] + b$ and $E[X + Y] = E[X] + E[Y]$, from the lesson on expected value. The second is that variances of independent variables add, $\operatorname{Var}(X + Y) = \operatorname{Var}(X) + \operatorname{Var}(Y)$, together with $\operatorname{Var}(aX + b) = a^2\operatorname{Var}(X)$; the next lesson proves it.

So standardizing pins down the center and the width. The content of the central limit theorem is what remains: the shape converges to the normal one. I cannot prove that here, and it is better to say why than to wave at it.

The standard proof attaches to each distribution a function called its characteristic function (a Fourier transform), which has two properties. Adding independent random variables multiplies their characteristic functions, so the one for a sum of $n$ copies is an $n$th power. And two distributions with nearly equal characteristic functions assign nearly equal probabilities to intervals (Lévy’s continuity theorem). The proof computes that the characteristic function of $Z_n$ is $\bigl(1 - \frac{t^2}{2n} + \text{smaller terms}\bigr)^n$, where only the mean and variance enter the terms shown. As $n$ grows this tends to $e^{-t^2/2}$, by the same limit that defines $e$, and $e^{-t^2/2}$ is the characteristic function of the standard normal. Each of those steps takes real analysis to justify. The theorem in this form is due to Lindeberg and Lévy in the 1920s; special cases for coins go back to de Moivre in 1733.

The theorem as stated gives no error estimate for a particular $n$. A companion result, the Berry–Esseen theorem, does: when $E[|X - \mu|^3]$ is finite, the error in $P(Z_n \le b)$ is at most a constant times $\frac{E[|X - \mu|^3]}{\sigma^3\sqrt n}$. Two consequences are worth remembering. The error shrinks like $1/\sqrt n$, which is slow. And it is larger for distributions that put weight far from the mean, relative to $\sigma$, which is why the bus needed more terms than the die.

Worked examples

How large is large enough?

Textbooks often say that $n \ge 30$ is enough for the central limit theorem. For sources like dice it is more than enough. But the theorem has no such threshold in it, and for a sufficiently lopsided source 30 is nowhere near enough.

Consider a scratch card that pays $100 with probability 0.01 and nothing otherwise. A card’s payout has mean $1 and standard deviation $\sqrt{0.01 \times 100^2 - 1^2} \approx \$9.95$: finite, so the theorem applies.

Pause and try

You buy 30 of these cards. What values can your average payout per card take, and what is the probability that it is exactly 0?

Show answerHide answer

The total is $100 times the number of winning cards, so the average is $0$, $3.33$, $6.67$ and so on in steps of $100/30$. It is 0 when all 30 cards lose, with probability $0.99^{30} \approx 0.74$. Three quarters of the time the average is 0, which is nothing like a bell centered at 1.

The exact distribution of the number of winning scratch cards, each winning with probability 0.01. With 30 cards, nearly all the probability is on zero or one winner, and no bell is in sight. With 3000 cards the distribution is close to normal.
The exact distribution of the number of winning scratch cards, each winning with probability 0.01. With 30 cards, nearly all the probability is on zero or one winner, and no bell is in sight. With 3000 cards the distribution is close to normal.
Monocurl source
let fa = Frame(-0.6, 4.6, 0, 0.82, [-1.85, 0, 0], 2.8, 2.6)
let fb = Frame(10, 52, 0, 0.082, [2.15, 0, 0], 2.8, 2.6)
mesh left = [
    GridLines(fa, [], [0.2, 0.4, 0.6, 0.8]),
    Seg(at(fa, -0.6, 0), at(fa, 4.6, 0), SLATE, 2.5),
    Seg(at(fa, -0.6, 0), at(fa, -0.6, 0.82), SLATE, 2.5),
    map([0, 1, 2, 3, 4], |k| center{[fx(fa, k), fy(fa, 0) - 0.3, 0]} Math(to_string(k), 0.74, SLATE)),
    map([0.2, 0.4, 0.6, 0.8], |v| center{[fx(fa, -0.6) - 0.35, fy(fa, v), 0]} Math(to_string(v, 1), 0.72, SLATE)),
    map(range(0, 5), |k| Box(at(fa, k, pmf(30, k, 0.01) / 2), [0.4, max(pmf(30, k, 0.01), 0.004) * 2.6 / 0.82], ROSE, 0.4, 2)),
    center{[fx(fa, 2), fy(fa, 0) - 0.68, 0]} Note("winning cards out of 30", 0.74),
    center{at(fa, 2.9, 0.5)} Cap("30 cards", 0.82, ROSE)
]
mesh right = [
    GridLines(fb, [], [0.02, 0.04, 0.06, 0.08]),
    Seg(at(fb, 10, 0), at(fb, 52, 0), SLATE, 2.5),
    Seg(at(fb, 10, 0), at(fb, 10, 0.082), SLATE, 2.5),
    map([10, 20, 30, 40, 50], |k| center{[fx(fb, k), fy(fb, 0) - 0.3, 0]} Math(to_string(k), 0.74, SLATE)),
    map([0.02, 0.04, 0.06, 0.08], |v| center{[fx(fb, 10) - 0.4, fy(fb, v), 0]} Math(to_string(v, 2), 0.72, SLATE)),
    map(range(11, 52), |k| Box(at(fb, k, pmf(3000, k, 0.01) / 2), [2.8 / 42 * 0.84, max(pmf(3000, k, 0.01), 0.0004) * 2.6 / 0.082], LEAF, 0.4, 1.5)),
    stroke{EMBER, 3.5} Polyline(map(sample(10, 52, 120), |x| at(fb, x, bell(x, 30, sqrt(3000 * 0.01 * 0.99))))),
    center{[fx(fb, 31), fy(fb, 0) - 0.68, 0]} Note("winning cards out of 3000", 0.74),
    center{at(fb, 43.5, 0.07)} Cap("3000 cards", 0.82, LEAF)
]
mesh top = center{[0, 1.85, 0]} Note("exact probabilities", 0.74)

Uses the shared definitions for this lesson's figures.

The theorem is true for the scratch card, and its promise is kept eventually: with 3000 cards the number of winners is close to normal. How large $n$ must be depends on how lopsided the source is.

A case where the theorem fails

Every hypothesis in a theorem should be tested by removing it. Here is what happens without a finite variance.

Stand one meter from a long wall, holding a flashlight. Spin around and stop at a random angle, facing the wall, so that the beam’s angle from the perpendicular is equally likely to be anything between $-90°$ and $90°$. Record the position $x$ where the beam hits the wall, in meters from the nearest point: $x = \tan(\text{angle})$. Most spins land within a meter or two. But angles near $\pm 90°$ send the beam almost parallel to the wall, and it lands enormously far away. The distribution of $x$ is called the Cauchy distribution, and its density is $\frac{1}{\pi(1 + x^2)}$.

Pause and try

Average the positions of 100 spins. Will the average be more tightly concentrated near 0 than a single spin is?

Show answerHide answer

For every distribution with a finite variance, yes: the spread of the average shrinks like $1/\sqrt n$. For this one, no. The next figure shows that the average of 100 spins has the same distribution as one spin.

A simulation of the flashlight experiment. Each panel is a histogram of 3000 averages of 1, 10 or 100 spins, with the Cauchy density drawn in orange. The three histograms are the same: averaging does not concentrate the result at all. The number is the share of averages between -1 and 1, which stays near one half.
A simulation of the flashlight experiment. Each panel is a histogram of 3000 averages of 1, 10 or 100 spins, with the Cauchy density drawn in orange. The three histograms are the same: averaging does not concentrate the result at all. The number is the share of averages between $-1$ and $1$, which stays near one half.
Monocurl source
let CT = 3000
let cauchy_counts = |n| {
    var c = map(range(0, 17), |i| 0)
    for (t in range(0, CT)) {
        var s = 0
        for (j in range(0, n)) {
            s = s + spin(t * n + j + 1, 200 + n)
        }
        let a = s / n
        if (a > -8 and a < 8) {
            c[to_int(floor(a + 8))] = c[to_int(floor(a + 8))] + 1
        }
        if (abs(a) <= 1) {
            c[16] = c[16] + 1
        }
    }
    return c
}
let Panel = |n, cx| {
    let c = cauchy_counts(n)
    let f = Frame(-8, 8, 0, 0.34, [cx, -0.1, 0], 2.05, 2.5)
    return [
        GridLines(f, [-4, 0, 4], [0.1, 0.2, 0.3]),
        Seg(at(f, -8, 0), at(f, 8, 0), SLATE, 2.5),
        map([-4, 0, 4], |v| center{[fx(f, v), fy(f, 0) - 0.3, 0]} Math(to_string(v), 0.72, SLATE)),
        map(range(0, 16), |b| Box(at(f, b - 7.5, c[b] / CT / 2), [2.05 / 16 * 0.92, max(c[b] / CT, 0.002) * 2.5 / 0.34], AZURE, 0.4, 1.5)),
        stroke{EMBER, 3.5} Polyline(map(sample(-8, 8, 120), |x| at(f, x, 1 / (PI * (1 + x * x))))),
        center{[cx, fy(f, 0.34) + 0.55, 0]} Cap(str_join(["average of ", to_string(n)]), 0.78, INK),
        center{[cx + 0.55, fy(f, 0.27), 0]} Math(to_string(c[16] / CT, 2), 0.95, AZURE)
    ]
}
mesh panels = [Panel(1, -2.3), Panel(10, 0.1), Panel(100, 2.5)]
mesh ticks = [
    map([0.1, 0.2, 0.3], |v| center{[-2.3 - 1.025 - 0.34, -0.1 + (v - 0.17) * 2.5 / 0.34, 0]} Math(to_string(v, 1), 0.72, SLATE)),
    center{[0.1, -2.02, 0]} Note("position on the wall (meters)", 0.74)
]

Uses the shared definitions for this lesson's figures.

This is a theorem, provable with the same characteristic functions: the average of $n$ independent Cauchy variables has exactly the Cauchy distribution, for every $n$. Averaging a hundred spins tells you no more than one spin does. The reason is that the rare enormous values are enormous enough to matter. A single spin near $90°$ can exceed the sum of all the others, and dividing by $n$ does not tame it.

Running averages over 5000 draws. The blue path averages draws from a standard normal distribution and settles at 0. The three red paths average flashlight spins. Each seems to settle, and then one huge value throws it somewhere else. These three runs are not typical: they were picked from twelve because they stay on the axes. Two of the twelve left the frame entirely, one thrown below $-2000$ and one above $1400$.
Monocurl source
let STEPS = 200
let PER = 25
let SALTS = [62, 64, 68]
var runs = []
for (r in range(0, 3)) {
    var s = 0
    var pts = []
    for (i in range(1, STEPS * PER + 1)) {
        s = s + spin(i, SALTS[r])
        if (mod(i, PER) == 0) {
            pts .= s / i
        }
    }
    runs .= pts
}
var ns = 0
var npts = []
for (i in range(1, STEPS * PER + 1)) {
    ns = ns + sqrt(-2 * ln(max(rnd(i, 81), 0.000000001))) * cos(TAU * rnd(i, 82))
    if (mod(i, PER) == 0) {
        npts .= ns / i
    }
}
let RUNS = runs
let NORMAL = npts
let fp = Frame(0, 5000, -9, 9, [0, 0.1, 0], 6.3, 3.0)
let COLS = [ROSE, tint(ROSE, 0.7), [0.55, 0.12, 0.2, 1]]
let Paths = |j| {
    let k = to_int(floor(j))
    var parts = []
    for (r in range(0, 3)) {
        parts .= stroke{COLS[r], 3} Polyline(map(range(0, k + 1), |m| at(fp, (m + 1) * PER, clamp(-9, RUNS[r][m], 9))))
    }
    parts .= stroke{AZURE, 3.5} Polyline(map(range(0, k + 1), |m| at(fp, (m + 1) * PER, NORMAL[m])))
    return parts
}
mesh frame = [
    GridLines(fp, [1000, 2000, 3000, 4000, 5000], [-8, -4, 0, 4, 8]),
    Seg(at(fp, 0, -9), at(fp, 0, 9), SLATE, 2.5),
    Seg(at(fp, 0, 0), at(fp, 5000, 0), SLATE, 2),
    map([1000, 2000, 3000, 4000, 5000], |v| center{[fx(fp, v), fy(fp, -9) - 0.28, 0]} Math(to_string(v), 0.72, SLATE)),
    map([-8, -4, 0, 4, 8], |v| center{[fx(fp, 0) - 0.33, fy(fp, v), 0]} Math(to_string(v), 0.72, SLATE)),
    center{[fx(fp, 2500), fy(fp, -9) - 0.62, 0]} Note("number of draws", 0.74),
    center{at(fp, 3700, 7.4)} Cap("running average", 0.78, INK),
    center{at(fp, 2100, -7.4)} Cap("flashlight spins", 0.78, ROSE),
    center{at(fp, 3900, -7.4)} Cap("normal draws", 0.78, AZURE)
]
mesh paths = Paths(j: 1)

slide "run"
    play Wait(0.5)
    paths.j = STEPS - 1
    play Lerp(8, [&paths], linear)
    play Wait(1.6)

Uses the shared definitions for this lesson's figures.

The hypothesis that fails is the finite variance. The Cauchy distribution has no variance, and in fact no mean. The mean would be $\int x \cdot \frac{1}{\pi(1 + x^2)}\,dx$ over the whole line, and already the right half of that integral is infinite: the area under $\frac{x}{\pi(1+x^2)}$ from 0 to $R$ is $\frac{1}{2\pi}\ln(1 + R^2)$, which grows without bound as $R$ does. (You can check the antiderivative by differentiating.) With no $\mu$ and no $\sigma$ there is nothing to standardize by, and neither the central limit theorem nor the law of large numbers applies.

The Cauchy case is extreme, but heavy tails are common in practice: insurance losses, city sizes, fluctuations of markets. When a quantity is dominated by rare huge values, averages behave badly and normal approximations are untrustworthy. The theorem’s other hypothesis matters too. If the values are strongly dependent, as when one measurement is copied $n$ times, the average is no better than a single value.

Stepping back

The surprising thing at the start was that a bell appeared from a die. The explanation has two layers. The elementary layer is counting: middling totals can be reached in many more ways than extreme ones. The deep layer is the theorem: after standardizing, the distribution of a sum of i.i.d. terms with finite variance converges to one universal shape, and it forgets everything about the terms except their mean and variance. We verified the mean and variance of $Z_n$, watched the convergence for a symmetric and a lopsided source, and cited the proof.

The practical use is the one in the worked examples: to find the probability that an average or a total lands in some range, compute its mean and standard deviation, convert to z-scores, and use normal areas, keeping in mind that the answer is an approximation whose quality depends on $n$ and on the tails. The next lesson applies this to the question of how a sample of a thousand people can speak for a country.

Check yourself

Individual waiting times at a clinic are strongly skewed to the right, with mean 20 minutes and standard deviation 20 minutes. Which statement does the central limit theorem support?

Problems

The first three use the theorem to compute. The next three are about its meaning and its hypotheses. The last two ask for exact calculations to compare with it.

Problem 1

For two dice, use the grid of 36 outcomes to find the probability that the average is (a) exactly 3.5, (b) at least 5.

Show solutionHide solution

(a) A total of 7: six outcomes, so $\frac{6}{36} = \frac16$. (b) A total of at least 10. Totals of 10, 11 and 12 occur in 3, 2 and 1 ways, so the probability is $\frac{6}{36} = \frac16$.

Problem 2

Fifty dice are rolled and their average is 3.9. Find the standard deviation of the average of fifty dice and the z-score of this result. Is it unusual?

Show solutionHide solution

The standard deviation of the average is $\frac{1.708}{\sqrt{50}} \approx 0.2415$. The z-score is $\frac{3.9 - 3.5}{0.2415} \approx 1.66$. By the central limit theorem the average is approximately normal, so a result this high or higher has probability between the one-sided tail areas for $z = 1$ and $z = 2$, that is, between 0.16 and 0.023. (A table gives about 0.05.) It is somewhat unusual and far from impossible.

Problem 3

An elevator is rated for 1900 kg. Twenty-five people get in. Suppose their weights are independent with mean 70 kg and standard deviation 15 kg. Estimate the probability that the total exceeds the rating. Which assumption would you question?

Show solutionHide solution

The total has mean $25 \times 70 = 1750$ kg and standard deviation $15\sqrt{25} = 75$ kg. The rating is $\frac{1900 - 1750}{75} = 2$ standard deviations above the mean, so by the normal approximation the probability is about $\frac{1 - 0.9545}{2} \approx 0.023$. Independence is the doubtful assumption: if the 25 people are a rugby team, or a group of children, their weights are not independent draws from the general population, and the total’s standard deviation of 75 kg is the wrong number.

Problem 4

How many dice must be averaged for the standard deviation of the average to be at most 0.1? What does this say about the cost of precision?

Show solutionHide solution

We need $\frac{1.708}{\sqrt n} \le 0.1$, so $\sqrt n \ge 17.08$ and $n \ge 291.7$: at least 292 dice. Thirty dice give a standard deviation of 0.31; cutting that by a factor of about 3 costs about 9 to 10 times as many dice, because the spread falls only like $1/\sqrt n$.

Problem 5

The heights of adult men are close to normal, but their incomes are far from it. Give an explanation of the difference in terms of the central limit theorem.

Show solutionHide solution

Height is plausibly the sum of a great many small, roughly independent contributions: many genes of small effect, nutrition at many stages, and so on. The theorem then predicts an approximately normal total. Income is not built by adding small independent amounts. Raises and returns on investment act as percentages, so effects multiply, and a few very large incomes carry a large share of the total. A product of many factors or a quantity dominated by rare large values has no reason to be normal. (The logarithm of a product is a sum, so the logarithm of income is closer to normal than income is.)

Problem 6

For each situation, say which hypothesis of the central limit theorem fails and what happens to the average of $n$ values. (a) A single die is rolled once and the result is written down $n$ times. (b) Every value equals 7. (c) The values are independent flashlight positions.

Show solutionHide solution

(a) Independence fails. The average equals the single roll, so its distribution is flat on 1 to 6 for every $n$ and never narrows. (b) The variance is zero, and the theorem requires $\sigma^2 > 0$. The average is always 7, and $Z_n$ would be $\frac00$, undefined. (c) The variance is not finite, and neither is the mean. The average has the same Cauchy distribution as a single value.

Problem 7

Three dice are rolled. (a) Show that a total of 10 can occur in 27 ways, and find its exact probability. (b) The total has mean 10.5 and standard deviation $\sqrt{3 \cdot 35/12} \approx 2.958$. The normal approximation to the probability of a total of exactly 10 is the area of a strip one unit wide, about $1 \times f(10)$, where $f$ is the normal density with that mean and standard deviation. Compute it, using $\varphi(0.169) \approx 0.3933$, and compare.

Show solutionHide solution

(a) List the totals by the first die. If it shows $a$, the other two must total $10 - a$, and the number of ways for two dice to total $t$ is $6 - |t - 7|$ for $2 \le t \le 12$. For $a = 1, \dots, 6$ the other two must total $9, 8, 7, 6, 5, 4$, in $4, 5, 6, 5, 4, 3$ ways: 27 in all. The probability is $\frac{27}{216} = 0.125$. (b) The z-score of 10 is $\frac{10 - 10.5}{2.958} \approx -0.169$, and $f(10) = \frac{1}{2.958}\varphi(-0.169) = \frac{0.3933}{2.958} \approx 0.133$. The approximation 0.133 is within 0.008 of the exact 0.125, with only three dice.

Problem 8

Two numbers $U$ and $V$ are chosen independently and uniformly at random from the interval $[0, 1]$, so that the point $(U, V)$ is uniformly distributed over the unit square and probabilities are areas. (a) Find $P\bigl(\frac{U + V}{2} \le \frac14\bigr)$. (b) Find $P\bigl(\frac{U+V}{2} \le t\bigr)$ for $0 \le t \le \frac12$. (c) Compare (a) with the probability that a single uniform number is at most $\frac14$, and explain the difference.

Show solutionHide solution

(a) The condition is $U + V \le \frac12$. In the unit square this is the triangle with corners $(0,0)$, $(\frac12, 0)$ and $(0, \frac12)$, whose area is $\frac12 \cdot \frac12 \cdot \frac12 = \frac18$. (b) The condition $U + V \le 2t$ with $2t \le 1$ cuts off a right triangle with legs $2t$, of area $\frac12(2t)^2 = 2t^2$. (c) A single uniform number is at most $\frac14$ with probability $\frac14$, twice as likely as the average of two. For the average to be small, both numbers must be small together, and the region where that happens is a small corner of the square. This is the two-dice triangle again in continuous form: the density of the average is the derivative of $2t^2$, which is $4t$, rising in a straight line toward the middle.

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 rnd = |i, salt| mod(seeded_random(i, salt) + 1, 1)
let roll = |i, salt| to_int(floor(6 * rnd(i, salt))) + 1
let DIE_SD = sqrt(35 / 12)
let phi = |z| exp(-z * z / 2) / sqrt(TAU)
let bell = |x, mu, sd| phi((x - mu) / sd) / sd
let NS = [1, 2, 3, 5, 10, 30]
let TRIALS = 10000
# roll n dice `trials` times. counts[s - n] is how often the total was s
let dice_counts = |n, trials| {
    var c = map(range(0, 5 * n + 1), |i| 0)
    for (t in range(0, trials)) {
        var s = 0
        for (j in range(0, n)) {
            s = s + roll(t * n + j + 1, n)
        }
        c[s - n] = c[s - n] + 1
    }
    return c
}
# standard deviation of the simulated averages
let avg_sd = |counts, n, trials| {
    var m = 0
    var q = 0
    for (i in range(0, 5 * n + 1)) {
        let a = (i + n) / n
        m = m + a * counts[i] / trials
        q = q + a * a * counts[i] / trials
    }
    return sqrt(q - m * m)
}
# histogram of the average of n dice, as fraction per unit. standard = 1 plots z-scores instead
let DiceBars = |fr, counts, n, trials, standard, col| block {
    let sdn = DIE_SD / sqrt(n)
    for (i in range(0, 5 * n + 1)) {
        let avg = (i + n) / n
        var x = avg
        var gap = 1 / n
        if (standard) {
            x = (avg - 3.5) / sdn
            gap = 1 / n / sdn
        }
        let h = counts[i] / trials / gap
        let hs = h * fr[6] / (fr[3] - fr[2])
        if (hs > 0.012 and x > fr[0] and x < fr[1]) {
            . Box(at(fr, x, h / 2), [gap * fr[5] / (fr[1] - fr[0]) * 0.9, hs], col, 0.4, 1.5)
        }
    }
}
# one simulated waiting time with mean 5 minutes (short waits most likely)
let wait = |i, salt| -5 * ln(max(rnd(i, salt), 0.000000001))
# one spin of the flashlight: where the beam hits the wall
let spin = |i, salt| tan(PI * (rnd(i, salt) - 0.5))
# chance of exactly k successes in n independent trials with success chance p
let pmf = |n, k, p| {
    var v = 1.0
    for (i in range(1, k + 1)) {
        v = v * (n - k + i) / i * p
    }
    for (i in range(0, n - k)) {
        v = v * (1 - p)
    }
    return v
}