15. ε–δ in practice

📖 Reading · 16 min
💡 Every code box below is live — edit it and hit Run.

You've been using limits for eight lessons on intuition. This one makes the definition do work.

You will not need \varepsilon\delta to compute a derivative or an integral — the rules handle that. You need it for three reasons: to know what the rules are claiming, to prove a limit is not something, and because every theorem in §15 is written in this language. Learning it once now is cheaper than meeting it cold later.

The definition, read as a game

\lim_{x\to a}f(x) = L means: for every \varepsilon > 0 there exists \delta > 0 such that 0 < |x - a| < \delta \implies |f(x) - L| < \varepsilon

Two players.

The challenger picks \varepsilon: "I want f(x) within 0.001 of L."

You respond with \delta: "Then keep x within \delta of a."

You win if your \delta works for every challenge. The challenger goes first, so your \delta is allowed to — and normally must — depend on \varepsilon.

The three pieces of notation:

  • |f(x) - L| < \varepsilon — how close the output must be. The target.
  • |x - a| < \delta — how close the input is allowed to be. Your lever.
  • 0 < |x-a|x \neq a. This is what encodes "ignore the value at the point", and it is why the definition works for \frac{f(x+h)-f(x)}{h} at h = 0.

The method

Every proof of this kind has the same two phases.

Phase 1: scratch work (backwards). Start from what you want, |f(x) - L| < \varepsilon, and manipulate until you have |x - a| < \text{something}. That something is your \delta.

Phase 2: the proof (forwards). State \delta, assume 0 < |x-a| < \delta, and derive |f(x)-L| < \varepsilon.

The scratch work is where the thinking happens; the written proof runs the reasoning in reverse. Textbooks show only phase 2, which is why these proofs look like they were pulled out of thin air.

A linear example

Prove \lim_{x\to2}(3x+1) = 7.

Scratch. We want |(3x+1) - 7| < \varepsilon. Simplify the left side:

|3x - 6| = 3|x-2|

So we want 3|x-2| < \varepsilon, i.e. |x-2| < \frac{\varepsilon}{3}. There's the \delta.

Proof. Let \varepsilon > 0 and set \delta = \frac{\varepsilon}{3}. If 0 < |x-2| < \delta then

|(3x+1)-7| = 3|x-2| < 3\delta = 3\cdot\frac{\varepsilon}{3} = \varepsilon \qquad\blacksquare

For any linear f(x) = mx+b with m \neq 0, the same computation gives \delta = \frac{\varepsilon}{|m|}: steeper functions need tighter input control, which is exactly what intuition says.

A quadratic example, where it gets interesting

Prove \lim_{x\to2}x^2 = 4.

Scratch. We want |x^2 - 4| < \varepsilon. Factor:

|x^2-4| = |x-2||x+2|

We control |x-2| directly. But |x+2| is also varying, and we can't just divide by it — \delta must be a number, not a function of x.

The fix is a two-stage trick used in essentially every nonlinear \varepsilon\delta proof: first restrict x to a convenient neighbourhood so the nuisance factor is bounded, then handle \varepsilon.

Insist \delta \le 1. Then |x-2| < 1 means 1 < x < 3, so

|x+2| < 5

With that in hand,

|x^2-4| = |x-2||x+2| < 5|x-2|

so it's enough to have |x-2| < \frac{\varepsilon}{5}.

Proof. Let \varepsilon > 0 and set

\delta = \min\!\left(1, \frac{\varepsilon}{5}\right)

If 0 < |x-2| < \delta then \delta \le 1 gives |x+2| < 5, and \delta \le \frac\varepsilon5 gives

|x^2-4| = |x-2||x+2| < \frac{\varepsilon}{5}\cdot 5 = \varepsilon \qquad\blacksquare

The \min is the whole technique. One clause tames the nonlinearity, the other delivers the tolerance. The choice of 1 is arbitrary — any convenient bound works, and the resulting \delta differs, which is fine. \delta is never unique. Any smaller \delta also works, so you only ever have to produce some \delta, never the best one.

Proving a limit is wrong

Negate the definition and you get a tool for disproof:

\lim_{x\to a}f(x) \neq L means: there exists \varepsilon > 0 such that for every \delta > 0, some x with 0<|x-a|<\delta has |f(x)-L| \ge \varepsilon.

The quantifiers flip. Now you pick the \varepsilon that can't be met, and the opponent's \delta is the one that fails.

Show \lim_{x\to0}\frac{|x|}{x} does not exist.

Suppose the limit were some L. Take \varepsilon = 1. Whatever \delta > 0 is offered, the interval (-\delta, \delta) contains both positive and negative points, where f takes the values +1 and -1. For both to lie within 1 of L we'd need |1 - L| < 1 and |-1-L| < 1, i.e. 0 < L < 2 and -2 < L < 0 — impossible.

So no L works, and the limit does not exist. \blacksquare

The pattern: find two sequences approaching a along which f has different limits. That's the practical form of the negation, and it's how you kill \sin(1/x) too.

Doing it in Python

You can't verify "for all \varepsilon" by machine, but you can watch a proposed \delta do its job:

def f(x):
    return 3 * x + 1

a, L = 2.0, 7.0

print(f"{'epsilon':>10} {'delta = eps/3':>16} {'worst |f(x)-L|':>18} {'holds':>8}")
for eps in (1.0, 0.1, 0.01, 0.001):
    delta = eps / 3
    worst = max(abs(f(a + s * delta * 0.999999) - L) for s in (-1, 1))
    print(f"{eps:>10} {delta:>16.8f} {worst:>18.10f} {worst < eps!s:>8}")

print("\nevery challenge is met, with room to spare at the boundary")

The quadratic, where a naive \delta fails and the \min saves it:

def f(x):
    return x * x

a, L = 2.0, 4.0

print("naive delta = eps (ignoring the |x+2| factor):")
for eps in (1.0, 0.5, 0.1):
    delta = eps
    worst = max(abs(f(a + s * delta * 0.999999) - L) for s in (-1, 1))
    print(f"  eps={eps:<6} delta={delta:<8} worst={worst:.6f}  holds={worst < eps}")

print("\ncorrect delta = min(1, eps/5):")
for eps in (1.0, 0.5, 0.1):
    delta = min(1, eps / 5)
    worst = max(abs(f(a + s * delta * 0.999999) - L) for s in (-1, 1))
    print(f"  eps={eps:<6} delta={delta:<8} worst={worst:.6f}  holds={worst < eps}")

Searching for the largest \delta that works, to see how much slack the proof leaves:

def largest_delta(f, a, L, eps, hi=2.0, steps=60):
    """Biggest d such that |f(x)-L| < eps for all 0 < |x-a| < d."""
    lo = 0.0
    for _ in range(steps):
        mid = (lo + hi) / 2
        ok = all(abs(f(a + s * mid * t) - L) < eps
                 for s in (-1, 1) for t in (0.25, 0.5, 0.75, 0.999999))
        lo, hi = (mid, hi) if ok else (lo, mid)
    return lo

print(f"{'eps':>8} {'proof delta':>14} {'largest delta':>16} {'slack':>10}")
for eps in (1.0, 0.5, 0.1, 0.01):
    proof = min(1, eps / 5)
    best = largest_delta(lambda x: x * x, 2.0, 4.0, eps)
    print(f"{eps:>8} {proof:>14.8f} {best:>16.8f} {best/proof:>10.3f}x")

print("\nthe proof's delta is conservative, and that is fine -- it only has to work")

Disproof by two sequences:

from math import sin, pi

print("sin(1/x) along two sequences, both running to 0:")
for k in (100, 1000, 10000):
    x1 = 1 / (k * pi)                 # sin = 0
    x2 = 1 / (pi / 2 + 2 * k * pi)    # sin = 1
    print(f"  k={k:<6} f({x1:.2e})={sin(1/x1):+.6f}   f({x2:.2e})={sin(1/x2):+.6f}")

print("\nwith eps=0.4, no single L can be within 0.4 of both 0 and 1.")
print("no delta can help: both sequences enter EVERY neighbourhood of 0.")

Worked example

Prove \lim_{x\to3}(x^2 + 1) = 10.

Scratch. Target: |x^2+1-10| = |x^2-9| = |x-3||x+3| < \varepsilon.

The nuisance factor is |x+3|. Restrict with \delta \le 1: then 2 < x < 4, so 5 < x+3 < 7, giving |x+3| < 7.

Now |x-3||x+3| < 7|x-3|, so |x-3| < \frac{\varepsilon}{7} suffices.

Proof. Let \varepsilon > 0. Choose

\delta = \min\!\left(1, \frac{\varepsilon}{7}\right)

Assume 0 < |x-3| < \delta. From \delta \le 1 we get |x-3| < 1, hence |x+3| = |(x-3) + 6| \le |x-3| + 6 < 7. Therefore

|(x^2+1) - 10| = |x-3|\,|x+3| < \frac{\varepsilon}{7}\cdot7 = \varepsilon \qquad\blacksquare

Two details worth copying. The bound |x+3| \le |x-3| + 6 is the triangle inequality, and it's the standard way to bound a nuisance factor without drawing a picture. And notice the proof never needed \delta to be optimal — a conservative bound that's easy to justify beats a sharp one that's hard.

Your turn

1. Prove \lim_{x\to1}(5x-3) = 2 by finding \delta in terms of \varepsilon.

2. For \lim_{x\to3}x^2 = 9 with \varepsilon = 0.1, find a specific \delta that works.

3. Prove \lim_{x\to0}\frac{1}{x} does not exist.

Solutions

1. Scratch. |(5x-3) - 2| = |5x - 5| = 5|x-1| < \varepsilon requires |x-1| < \frac{\varepsilon}{5}.

Proof. Given \varepsilon > 0, take \delta = \frac{\varepsilon}{5}. If 0 < |x-1| < \delta then

|(5x-3)-2| = 5|x-1| < 5\cdot\frac{\varepsilon}{5} = \varepsilon \qquad\blacksquare

2. From the worked example's method with a = 3: $\delta = \min(1, \frac{\varepsilon}{7})$, so for \varepsilon = 0.1,

\delta = \min\!\left(1, \frac{0.1}{7}\right) = \frac{1}{70} \approx 0.0142857

Check the worse endpoint, x = 3 + \delta:

|(3.0142857)^2 - 9| = |9.0859 - 9| = 0.0859 < 0.1 \quad\checkmark

There's slack, as expected — the bound |x+3| < 7 was generous, since near x=3 the factor is really about 6. Using 6.1 would give a larger \delta. Both are correct proofs.

3. Suppose \lim_{x\to0}\frac1x = L for some real L. Take \varepsilon = 1.

Given any \delta > 0, pick x with $0 < x < \min\left(\delta, \frac{1}{|L|+2}\right)$. Then x is inside the \delta-neighbourhood, and

\frac1x > |L| + 2

so

\left|\frac1x - L\right| \ge \frac1x - |L| > 2 > 1 = \varepsilon

The condition fails for every \delta, so no real L can be the limit. \blacksquare

The essential point is that \frac1x is unbounded near 0, and no finite L can stay within a fixed tolerance of something unbounded. Compare the jump case \frac{|x|}{x}, where the function is bounded and the failure was disagreement rather than blow-up — two different failure modes, two different disproofs.

Check yourself in code

Verify that \delta = \varepsilon/3 certifies \lim_{x\to2}(3x+1) = 7, and that the naive \delta = \varepsilon fails for \lim_{x\to2}x^2 = 4 while \delta = \min(1, \varepsilon/5) succeeds.

For each \varepsilon \in \{1, 0.5, 0.1, 0.01\}, evaluate the worst deviation |f(x) - L| at x = a \pm 0.999999\delta and report whether it stays below \varepsilon.

Print exactly this:

linear   eps=1      delta=0.333333  worst=0.999999  ok=True
linear   eps=0.5    delta=0.166667  worst=0.500000  ok=True
linear   eps=0.1    delta=0.033333  worst=0.100000  ok=True
linear   eps=0.01   delta=0.003333  worst=0.010000  ok=True
naive    eps=1      delta=1.000000  worst=4.999994  ok=False
naive    eps=0.5    delta=0.500000  worst=2.249998  ok=False
naive    eps=0.1    delta=0.100000  worst=0.410000  ok=False
naive    eps=0.01   delta=0.010000  worst=0.040100  ok=False
min      eps=1      delta=0.200000  worst=0.839999  ok=True
min      eps=0.5    delta=0.100000  worst=0.410000  ok=True
min      eps=0.1    delta=0.020000  worst=0.080400  ok=True
min      eps=0.01   delta=0.002000  worst=0.008004  ok=True
EPS = (1, 0.5, 0.1, 0.01)

def worst(f, a, L, delta):
    return max(abs(f(a + s * delta * 0.999999) - L) for s in (-1, 1))

linear = lambda x: 3 * x + 1
square = lambda x: x * x

for eps in EPS:
    d = eps / 3
    print(f"linear   eps={eps:<6} delta={d:.6f}  worst={worst(linear, 2, 7, d):.6f}  "
          f"ok={worst(linear, 2, 7, d) < eps}")

# now the naive delta = eps for x^2, then delta = min(1, eps/5)
EPS = (1, 0.5, 0.1, 0.01)

def worst(f, a, L, delta):
    return max(abs(f(a + s * delta * 0.999999) - L) for s in (-1, 1))

linear = lambda x: 3 * x + 1
square = lambda x: x * x

for eps in EPS:
    d = eps / 3
    w = worst(linear, 2, 7, d)
    print(f"linear   eps={eps:<6} delta={d:.6f}  worst={w:.6f}  ok={w < eps}")

for label, rule in (("naive", lambda e: e), ("min", lambda e: min(1, e / 5))):
    for eps in EPS:
        d = rule(eps)
        w = worst(square, 2, 4, d)
        print(f"{label:<8} eps={eps:<6} delta={d:.6f}  worst={w:.6f}  ok={w < eps}")

The definition is a two-player game: the challenger names a tolerance \varepsilon, you produce a radius \delta, and you win by answering every challenge. Find \delta by working backwards from |f(x)-L| < \varepsilon; for nonlinear functions, use $\delta = \min(\text{something convenient}, \text{something}/\varepsilon\text{-dependent})$ so the first clause bounds the nuisance factor and the second delivers the tolerance. Negating the definition gives you disproofs, and in practice that means exhibiting two sequences with different limits.

That closes the foundations. Next module: the derivative — which is a single specific limit, taken seriously.