You can draw the graph without lifting your pen — nudge the input a little and the output only moves a little. This chapter turns that hand-wave into an airtight promise: the ε–δ definition, the theorems it unlocks, and the code that leans on them.
Continuity is the property that makes a function trustworthy near a point: if you don't move the input much, the output won't surprise you. It's the difference between a smooth dial and a light switch — and once we pin it down precisely, three of the workhorse theorems of analysis fall right out.
You already have a feel for this. A temperature curve is continuous; the floor number on an elevator display is not — it jumps from 3 to 4 with nothing in between. This chapter makes the intuition exact, then shows why continuous functions are the ones you can actually compute with.
Here's the whole idea in one sentence: a small change in the input causes only a small change in the output. Nudge x a hair and f(x) shifts a hair — never a sudden leap.
The picture everyone carries around is exactly right: you can draw the graph without lifting your pen. No breaks, no teleporting, no vertical cliffs. If your pen has to jump off the paper to get from one part of the curve to the next, the function is discontinuous at that spot.
Compare two functions of a dial position. f(x) = x² is continuous — turn the dial slightly and the reading drifts slightly. A step function step(x) = 0 for x < 0, else 1 is not — right at 0 the output teleports from 0 to 1 with nothing between. That leap is the enemy. Everything in this chapter is about ruling it out with a promise precise enough to check.
x₀ first; it's called continuous everywhere only if it passes the test at every point. The step function is perfectly continuous away from 0 — it fails at exactly one spot, and one bad spot is enough to disqualify it there."Small change in, small change out" is the feeling. To make it a definition we need to say how small — and the trick is to let the reader demand the output precision first.
Think of it as a guarantee with a knob. You point at a target width around the output — "keep f(x) within ε of f(x₀)" — and continuity promises there's a matching width around the input — "as long as x stays within δ of x₀" — that delivers it. Formally:
For every ε > 0 there is a δ > 0 such that
whenever |x − x₀| < δ, we have |f(x) − f(x₀)| < ε.
Read it slowly. ε is the output tolerance the challenger picks — how close is close enough. δ is the input tolerance you find in response — how tightly you have to pin the input to hit it. Continuity says the response always exists, no matter how tiny the demand. A jump breaks the promise: below a certain ε, the two sides of the leap can never both fit in the band, so no δ can save you.
The definition is easiest to feel as a two-player game. An adversary names a tolerance ε — a horizontal band of half-height ε around f(x₀) — and dares you to keep the output inside it. You answer with a δ: a window around x₀ narrow enough that the curve never escapes the band.
Continuity means you can always answer. Whatever ε the adversary shrinks to, a working δ exists. Drag ε below and watch the widest winning δ appear. Then flip the switch to a jump: shrink ε past the gap and the band escapes no matter how tiny your window gets — no δ exists, and that verdict is exactly what "discontinuous" means.
The pattern to notice: as the adversary tightens ε, the winning δ shrinks too — but for a continuous function it stays positive, always. That "there's still room to answer" is the whole content of continuity, and it's why the definition leads with for every ε.
Discontinuity comes in a few distinct flavors. Knowing the zoo helps you spot which promise got broken.
(x² − 1)/(x − 1) at x = 1, which wants to be 2 but is undefined there. One dot in the wrong place; "remove" it by filling the hole and continuity returns.sin(1/x) near 0 doesn't jump to a wrong value — it refuses to settle on any value at all. As x → 0 the argument 1/x races to infinity, so the curve crams infinitely many full up-and-down swings into any window around 0. There's no limit to approach, so no f(0) could ever make it continuous.All three fail the same test from Section 2 — you can find an ε small enough that no δ answers it — but they fail it in different shapes: a clean leap, a lone bad point, or a value that never converges.
sin(1/x) is genuinely defined and continuous for every x ≠ 0 — the trouble is confined to a single point it can't reach. No matter what value you assign at 0, some sequence xₙ → 0 sends f(xₙ) bouncing between −1 and 1. That's the sequence test failing, which is where we go next.There's a second definition of continuity, and if you did Chapter 2 it'll feel like home. Instead of ε and δ, use the sequences you already know how to reason about:
f is continuous at x₀ exactly when:
every sequence xₙ → x₀ forces f(xₙ) → f(x₀).
In plain terms: continuous functions carry convergence across. If your inputs are homing in on x₀, a continuous f guarantees the outputs home in on f(x₀) — the limit passes straight through the function, f(lim xₙ) = lim f(xₙ). That's an enormously useful license: it lets you swap "take the limit" and "apply f" whenever f is continuous.
And it's exactly the tool that convicts sin(1/x). Take xₙ = 1/(nπ), which tends to 0 with f(xₙ) = 0; then take xₙ = 2/((4n+1)π), also tending to 0 but with f(xₙ) = 1. Two input sequences reaching the same place, two different output destinations — the promise is broken, so no value at 0 makes it continuous. The sequence definition and the ε–δ definition are provably equivalent; pick whichever is easier for the problem in front of you.
Now the payoffs. If a continuous function starts below a value and ends above it, it must hit it somewhere in between — it can't skip over, because skipping would be a jump, and continuity forbids jumps.
If f is continuous on [a, b], then for every value y between f(a) and f(b)
there is some c in [a, b] with f(c) = y.
No gaps in the output: sweep from f(a) up to f(b) and the function takes on every height along the way. The most useful special case is y = 0: if f(a) and f(b) have opposite signs, the curve crosses zero somewhere between them. A sign change traps a root.
[lo, hi], cut the interval in half, and keep the half that still straddles zero. IVT guarantees a root lives in whichever half you keep, so the bracket can never lose it. And it's Chapter 1's completeness that guarantees the shrinking brackets close on an actual real number — the root you were hunting is genuinely there to be found.Here's that argument as running code. A continuous function plus a sign change is all bisection needs; the shape is identical in Scala and Haskell.
f is continuous. Feed bisection a jump function that flips sign by leaping across zero without touching it, and the code will happily return a "root" that is nothing of the kind — the theorem's hypothesis is doing real work, not decoration.One more guarantee, and it's the one optimization quietly depends on. On a closed, bounded interval a continuous function doesn't just approach its highest and lowest values — it actually reaches them.
If f is continuous on a closed bounded interval [a, b],
then f attains a maximum and a minimum on [a, b].
"Attains" is the load-bearing word. There's an actual point c where f(c) is as big as f ever gets — a real argmax, not just a ceiling it sneaks up on. Every hypothesis earns its keep: drop continuous and a jump can leap over the peak; drop closed and f(x) = x on the open interval (0, 1) gets arbitrarily close to 1 while never touching it; drop bounded and f(x) = x on [0, ∞) has no maximum at all.
Together, IVT and EVT are why continuous functions on nice intervals are so tame: the output has no gaps (IVT) and no missing extremes (EVT). That combination — nothing skipped, nothing unreachable — is the reason so many algorithms assume continuity before they promise to converge.