Skip to content

Differentiation of Univariate Functions

Chapter 4 asked what is inside a matrix. This chapter asks how a function changes, and it starts where every calculus course starts — one input, one output — because everything later is that idea with more indices.

There are two things on this page. The derivative as the limit of a difference quotient, which you have met; and the Taylor series, which turns a function into a polynomial you can differentiate, integrate and reason about. The second is the one that does the work in the rest of the book: linearisation in §5.8, the Laplace approximation in Chapter 6, and the quadratic models that Chapter 7’s optimisers are built on are all Taylor expansions stopped early.

  • Definition 5.1 and 5.2: the difference quotient, and the derivative as its limit.
  • Why the limit is a definition and not an algorithm — measured, with the exact step size where a finite difference stops improving.
  • Definition 5.3: the Taylor polynomial TnT_n, and Definition 5.4: the Taylor series TT_\infty.
  • Why a Taylor polynomial of degree nn reproduces a polynomial of degree nn exactly, with every later coefficient zero.
  • The thing most treatments skip: near x0x_0 the error falls with degree; far from x0x_0 it grows.
  • §5.1.2’s four differentiation rules, and the one that matters most later — the chain rule.

Pick a point on a curve and a second point a distance hh away. The straight line through them has a slope you can compute from two function values and a division. Now slide the second point towards the first. The secant turns, and — if the function is smooth — it settles on a particular line. Its slope is the derivative.

That is the whole idea, and it is worth noticing what it does not say. It does not say “compute the slope for a small hh”. It says the slopes converge, and the derivative is the thing they converge to. Those are different claims, and on a computer the difference is the subject of half this page.

diagram Diagram mermaid

The difference quotient and the derivative

Section titled “The difference quotient and the derivative”

The book works Example 5.2 — the derivative of f(x)=xnf(x) = x^n — straight from Definition 5.2 rather than quoting the power rule, and the point of that exercise is the binomial expansion: every term with hi1h^{i-1} for i2i \geq 2 vanishes in the limit, leaving (n1)xn1=nxn1\binom{n}{1}x^{n-1} = nx^{n-1}.

The book’s Remark after Definition 5.4 is the one to hold on to: in general, a Taylor polynomial of degree nn is an approximation of a function, which does not need to be a polynomial. The Taylor polynomial is similar to ff in a neighbourhood around x0x_0. However, a Taylor polynomial of degree nn is an exact representation of a polynomial ff of degree n\leq n.

Two words there earn their place. “Neighbourhood” — the guarantee is local, and the measurements below show exactly how local. “Exact” — for a polynomial, TnT_n is not an approximation at all.

§5.1.2 lists four, and the chain rule is the one the rest of the chapter is built from:

rulestatement
product(fg)=fg+fg(fg)' = f'g + fg'
quotient(fg)=fgfgg2\left(\dfrac{f}{g}\right)' = \dfrac{f'g - fg'}{g^2}
sum(f+g)=f+g(f + g)' = f' + g'
chain(g(f(x)))=g(f(x))f(x)\bigl(g(f(x))\bigr)' = g'(f(x))\,f'(x)

Example 5.3 — x to the fourth, expanded at 1

Section titled “Example 5.3 — x to the fourth, expanded at 1”

f(x)=x4f(x) = x^4, so f(1)=1f(1) = 1, f(1)=4f'(1) = 4, f(1)=12f''(1) = 12, f(1)=24f'''(1) = 24, f(4)(1)=24f^{(4)}(1) = 24, and f(5)=0f^{(5)} = 0 identically. Dividing by k!k!:

kkf(k)(1)f^{(k)}(1)k!k!coefficient
0111111
1441144
212122266
324246644
42424242411
50012012000
T4(x)=1+4(x1)+6(x1)2+4(x1)3+(x1)4T_4(x) = 1 + 4(x-1) + 6(x-1)^2 + 4(x-1)^3 + (x-1)^4

Those coefficients are 1,4,6,4,11, 4, 6, 4, 1 — the fourth row of Pascal’s triangle, which is exactly what the binomial theorem says ((x1)+1)4\bigl((x-1) + 1\bigr)^4 should give. So T4=x4=fT_4 = x^4 = f, and every coefficient past the fourth is zero.

Measured over [0.6,2.6][-0.6, 2.6]: the largest fT4|f - T_4| is 7.11×10157.11\times10^{-15} — machine noise, and it does not change at T5T_5 or T6T_6.

Example 5.4 — sin plus cos, expanded at 0

Section titled “Example 5.4 — sin plus cos, expanded at 0”

The derivatives cycle with period four. Since f(k)(x)=sin(x+kπ/2)+cos(x+kπ/2)f^{(k)}(x) = \sin(x + k\pi/2) + \cos(x + k\pi/2), at x=0x = 0:

f(k)(0)=sinkπ2+coskπ2=+1,+1,1,1,+1,+1,f^{(k)}(0) = \sin\tfrac{k\pi}{2} + \cos\tfrac{k\pi}{2} = +1, +1, -1, -1, +1, +1, \dots

so

T5(x)=1+xx22!x33!+x44!+x55!=1+x12x216x3+124x4+1120x5T_5(x) = 1 + x - \frac{x^2}{2!} - \frac{x^3}{3!} + \frac{x^4}{4!} + \frac{x^5}{5!} = 1 + x - \tfrac{1}{2}x^2 - \tfrac{1}{6}x^3 + \tfrac{1}{24}x^4 + \tfrac{1}{120}x^5

This is Exercise 5.4, and it is done.

Here is the part that is usually left out. Measure fTn|f - T_n| twice: once on a tight interval x0.5|x| \leq 0.5 around the expansion point, and once on x4|x| \leq 4.

nnmax error, x0.5\lvert x\rvert \leq 0.5max error, x4\lvert x\rvert \leq 4
05.93×1015.93\times10^{-1}2.412.41
11.39×1011.39\times10^{-1}6.416.41
22.22×1022.22\times10^{-2}11.1011.10
32.69×1032.69\times10^{-3}12.2612.26
42.62×1042.62\times10^{-4}10.2310.23
52.13×1052.13\times10^{-5}6.946.94

The left column falls by roughly a factor of ten per degree. The right column rises, more than quadrupling from n=0n=0 to n=3n=3, before turning around. A Taylor polynomial buys accuracy near a point by giving it up away from it, and any statement that “more terms is better” is missing the qualifier.

sketch The secant becomes the tangent p5.js
Drag h and watch the secant through (x, f(x)) and (x+h, f(x+h)) rotate onto the tangent. The readout is the slope of the secant against the exact derivative. Drag x to move the point, and note that the convergence is fastest where the curve is straightest.
sketch Taylor polynomials, one degree at a time p5.js
Drag the degree and watch the polynomial wrap itself around the function near x0. The two error readouts are the point: the one measured near x0 falls every time you add a term, the one measured across the whole window does not. Switch functions to see a polynomial become exact.
fieldExample 5.4 and Exercise 5.4, one degree at a timeTaylor polynomials, §5.1.1
-4-3-2-101234-2-1012xf(x)x0 = 0fT_0
T_0(x) = 1
degree 0 of 5|f − T| within ±0.5 6.02e-1on the whole window 2.4142local order h^1
a0 1a1 1a2 -0.5a3 -0.166667a4 0.041667a5 0.008333a6 -0.001389a7 -0.000198
T_n(x0) = f(x0) 0.0e+0
degree0|f − T_n| near x06.02e-1on the whole window2.414
Degree 0: T_0 is the constant f(x0) = 1 — a horizontal line touching f at exactly one point. error within ±0.5 of x0 is 6.02e-1.
1/6

The coefficients cycle +1, +1, −1, −1. Each frame reports the local order of the error, derived from the first nonzero coefficient not yet used rather than assumed to be n+1.

fieldExample 5.3: a polynomial, expanded at x₀ = 1Taylor polynomials, §5.1.1
-0.500.511.522.5-20-100102030405060xf(x)x0 = 1fT_0
T_0(x) = 1
degree 0 of 6|f − T| within ±0.27 1.57e+0on the whole window 44.6976local order h^1
a0 1a1 4a2 6a3 4a4 1a5 0a6 0a7 0a8 0
T_n(x0) = f(x0) 0.0e+0coefficients past degree 4 all zero
degree0|f − T_n| near x01.57e+0on the whole window44.70
Degree 0: T_0 is the constant f(x0) = 1 — a horizontal line touching f at exactly one point. error within ±0.26666666666666666 of x0 is 1.57e+0.
1/7

Watch degree 4. The error drops to machine noise and the last two frames change nothing, because every remaining coefficient is exactly zero.

The obvious way to get f(k)(x0)f^{(k)}(x_0) numerically is to difference kk times. It does not work, and the reason is worth seeing.

taylor_from_scratch.py
import math
import numpy as np
 
def coeffs_by_differencing(f, x0, K, h=1e-3):
    """Repeated central differences. Loses about 8 digits per order."""
    out = []
    for k in range(K + 1):
        # The k-th central difference, from the binomial stencil.
        acc = 0.0
        for j in range(k + 1):
            acc += (-1) ** j * math.comb(k, j) * f(x0 + (k / 2 - j) * h)
        out.append(acc / h ** k / math.factorial(k))
    return out
 
def coeffs_by_jet(x0, K):
    """Truncated-Taylor arithmetic for sin(x) + cos(x): exact at every order."""
    s = [0.0] * (K + 1)
    c = [0.0] * (K + 1)
    s[0], c[0] = math.sin(x0), math.cos(x0)
    u = [0.0] * (K + 1)
    u[0], u[1] = x0, 1.0
    for k in range(1, K + 1):
        ss = sum(j * u[j] * c[k - j] for j in range(1, k + 1))
        cc = sum(j * u[j] * s[k - j] for j in range(1, k + 1))
        s[k], c[k] = ss / k, -cc / k
    return [s[k] + c[k] for k in range(K + 1)]
 
K = 8
exact = [(math.sin(k * math.pi / 2) + math.cos(k * math.pi / 2)) / math.factorial(k)
         for k in range(K + 1)]
diff = coeffs_by_differencing(lambda x: math.sin(x) + math.cos(x), 0.0, K)
jet = coeffs_by_jet(0.0, K)
 
print(f"{'k':>2}  {'exact':>14}  {'by differencing':>16}  {'error':>10}  {'by jet':>14}  {'error':>10}")
for k in range(K + 1):
    print(f"{k:>2}  {exact[k]:>14.10f}  {diff[k]:>16.10f}  {abs(diff[k]-exact[k]):>10.1e}"
          f"  {jet[k]:>14.10f}  {abs(jet[k]-exact[k]):>10.1e}")
output
 k           exact   by differencing       error          by jet       error
 0    1.0000000000      1.0000000000     0.0e+00    1.0000000000     0.0e+00
 1    1.0000000000      0.9999999583     4.2e-08    1.0000000000     0.0e+00
 2   -0.5000000000     -0.4999999583     4.2e-08   -0.5000000000     5.6e-17
 3   -0.1666666667     -0.1666666805     1.4e-08   -0.1666666667     5.6e-17
 4    0.0416666667      0.0416426153     2.4e-05    0.0416666667     6.9e-18
 5    0.0083333333      0.0138777878     5.5e-03    0.0083333333     1.7e-18
 6   -0.0013888889      5.5511151231     5.6e+00   -0.0013888889     4.3e-19
 7   -0.0001984127  -1299.6658423191     1.3e+03   -0.0001984127     8.1e-20
 8    0.0000248016  -225789.4048096796     2.3e+05    0.0000248016     1.0e-20

Read the two error columns, and then read the differencing column itself, because the failure is worse than “inaccurate”.

Differencing holds up to about k=4k = 4. Then it does not merely lose precision, it loses the answer:

kktrue coefficientby differencing
5+0.008333+0.008333+0.013878+0.013878
60.001389-0.001389+5.551\mathbf{+5.551}
70.000198-0.0001981299.67\mathbf{-1299.67}
8+0.0000248+0.0000248225789.4\mathbf{-225789.4}

At k=6k = 6 the sign is wrong and the magnitude is out by a factor of four thousand. At k=8k = 8 it is out by ten orders of magnitude. This is not an approximation that has degraded; it is noise multiplied by h8=1024h^{-8} = 10^{24}.

The jet column is exact at every order, and the reason is that it never subtracts two nearly equal numbers. Each recurrence is an algebraic identity between coefficients, so the chain rule is applied symbolically and evaluated numerically. That is also, precisely, forward-mode automatic differentiation — which is the connection §5.6 makes explicit.

figure Definition 5.1 converging to Definition 5.2 matplotlib
A curve with four dashed secant lines through a fixed point and a second point at decreasing distances, converging onto a heavy tangent line, with a table of secant slopes. A curve with four dashed secant lines through a fixed point and a second point at decreasing distances, converging onto a heavy tangent line, with a table of secant slopes.
Four secants at h = 1.6, 0.8, 0.4 and 0.2, with slopes 1.074466, 1.170422, 1.220578 and 1.239402 against an exact derivative of 1.251610. Each halving of h roughly halves the remaining error — that is what first-order convergence looks like.
figure The half of Definition 5.2 you cannot execute matplotlib
A log-log plot of derivative estimation error against step size, with forward and central difference curves each falling then rising, forming a V, and reference lines of slope one and two. A log-log plot of derivative estimation error against step size, with forward and central difference curves each falling then rising, forming a V, and reference lines of slope one and two.
Truncation error falls as h shrinks; round-off error rises. The best forward difference is 2.62e-10 at h = 1.5e-08 and the best central one is 2.88e-13 at h = 2.7e-06. At h = 1e-15 the central estimate is off by 8.07e-02 — 2.8e+11 times worse than its own best.
figure Example 5.4, with the error measured twice matplotlib
Left, sin x plus cos x with its Taylor polynomials of degree zero through five overlaid and a shaded band near the origin. Right, two error curves against degree on a log scale, one falling steeply and one rising then falling. Left, sin x plus cos x with its Taylor polynomials of degree zero through five overlaid and a shaded band near the origin. Right, two error curves against degree on a log scale, one falling steeply and one rising then falling.
Near x0 the error falls by about a factor of ten per degree, from 5.93e-01 at T0 to 2.13e-05 at T5. Across the whole interval it rises from 2.41 to 12.26 by degree 3 before coming back down — the polynomials get better near the centre by getting worse at the edges.

From the secant figure. The convergence is visible but the rate is the thing to extract. The errors are 0.1770.177, 0.0810.081, 0.0310.031 and 0.0120.012 for h=1.6,0.8,0.4,0.2h = 1.6, 0.8, 0.4, 0.2 — each roughly half the previous. Halving hh halves the error, so the forward difference is first order, and the leading error term is h2f(x)\frac{h}{2}f''(x). That is also why the error is smaller for the same hh where the curve is straighter.

From the round-off figure. This is the figure that changes how you write code.

The forward difference has error h2f+2εfh\approx \frac{h}{2}|f''| + \frac{2\varepsilon|f|}{h} — truncation falling like hh, round-off rising like 1/h1/h. The sum has a minimum, and it is not at the smallest representable hh:

best hhbest error
forward difference1.5×1081.5\times10^{-8}2.62×10102.62\times10^{-10}
central difference2.7×1062.7\times10^{-6}2.88×10132.88\times10^{-13}

Two consequences. First, hε1.5×108h \approx \sqrt{\varepsilon} \approx 1.5\times10^{-8} is the classic forward-difference rule of thumb, and the measurement lands on it. Second, the central difference is not merely better — it is better by three orders of magnitude, for one extra function evaluation. If you are ever going to difference numerically, difference centrally.

And the failure mode is severe: at h=1015h = 10^{-15} the central estimate is wrong by 8×1028\times10^{-2}, which is 2.8×10112.8\times10^{11} times worse than its own best. A gradient check that “uses a really small h to be safe” is not being safe.

From the Taylor figure. The two curves on the right go in opposite directions, and the reason is that a Taylor polynomial is a local object. TnT_n matches ff to order nn at x0x_0 and is under no obligation anywhere else — and a degree-nn polynomial has to do something as x|x| grows, which for sinx+cosx\sin x + \cos x (bounded) means running away.

The left column of the table is the guarantee: a factor of about ten per degree on x0.5|x| \leq 0.5. The right column is the small print.

way to get a derivativeexactnesscostneeds
by hand, symbolicallyexactyour timea closed form, and care
forward differenceO(h)O(h), floor 1010\approx 10^{-10}1 extra evaluationnothing
central differenceO(h2)O(h^2), floor 1013\approx 10^{-13}2 extra evaluationsnothing
jet / forward-mode ADexact to machine precision2×\approx 2\times the functionthe code, not the formula
reverse-mode AD (§5.6)exact to machine precision2.5×\approx 2.5\times the function, all inputs at oncea computation graph
complex-stepO(h2)O(h^2) with no cancellation1 complex evaluationan analytic function

The middle two rows are the ones this page is about. The bottom three are §5.6, and the reason the chapter goes there.

pch.quizTag Check your understanding
  1. Definition 5.2 says the derivative is the limit of the difference quotient. Why can that not be executed directly in floating point?

    pch.quizShowAnswer

    B — Because the truncation error falls like h while the round-off error from subtracting two nearly equal numbers rises like 1/h, so the total has a minimum at a specific h — measured here at 1.5e-08 for a forward difference — At h = 1e-15 the central difference on this page is wrong by 8e-02, which is 2.8e+11 times worse than its own best at h = 2.7e-06. Making h smaller past the optimum makes things worse, not better.

  2. A central difference costs one extra function evaluation over a forward difference. What does that buy?

    pch.quizShowAnswer

    B — Second-order rather than first-order convergence, and a floor three orders of magnitude lower: 2.9e-13 against 2.6e-10 on this page — The h-squared error term comes from the odd-order terms cancelling between f(x+h) and f(x-h). It is close to free, so if you are differencing numerically at all, difference centrally.

  3. Why is T_4 of x^4 at x0 = 1 not an approximation?

    pch.quizShowAnswer

    B — Because a Taylor polynomial of degree n reproduces a polynomial of degree at most n exactly — the coefficients 1, 4, 6, 4, 1 are the binomial expansion of ((x-1)+1)^4, and every coefficient past the fourth is exactly zero — Measured max error over the window: 7.11e-15, unchanged at degrees 5 and 6. The book states this in the Remark after Definition 5.4.

  4. Adding Taylor terms drove the sigmoid's maximum error on [-6, 6] from 0.5 up to 46. Is something wrong?

    pch.quizShowAnswer

    B — No. Each polynomial is strictly better near x0 — the error there falls monotonically — and a Taylor polynomial promises nothing away from the expansion point. A degree-7 polynomial has to grow without bound, and a bounded function does not — Near x0 the sigmoid's error falls 1.2e-1, 2.5e-3, 2.5e-3, 6.3e-5, ... every added term helps locally. Quoting a Taylor error without naming the interval is the mistake, not the polynomial.

  5. The from-scratch table gets the 6th Taylor coefficient as +5.551 instead of -0.001389 using repeated differences, but exactly using jets. What is the difference?

    pch.quizShowAnswer

    B — The jet uses no step at all. Its recurrences are algebraic identities between coefficients, so the chain rule is applied symbolically and only evaluated numerically — nothing nearly-equal is ever subtracted — The k-th difference divides by h to the k, so at h = 1e-3 and k = 8 it multiplies surviving round-off by 1e24 — the 8th coefficient came out as -225789 instead of +0.0000248. Jet arithmetic truncated at order 1 is exactly forward-mode automatic differentiation, which is where §5.6 goes.

Exercise 1 – The secant converging, and then not

Section titled “Exercise 1 – The secant converging, and then not”

Exercise 4 – Why repeated differencing fails

Section titled “Exercise 4 – Why repeated differencing fails”

Exercise 5 – Jets: exact coefficients at every order

Section titled “Exercise 5 – Jets: exact coefficients at every order”
  • The difference quotient is the slope of a secant; the derivative is the limit of those slopes, and the limit is a definition rather than an algorithm.
  • A forward difference is first order and a central difference second order. Measured: best forward error 2.6e-10 at h = 1.5e-08, best central 2.9e-13 at h = 2.7e-06 — three orders better for one extra function evaluation.
  • Making h smaller past the optimum makes things worse. At h = 1e-15 the central estimate is 2.8e+11 times worse than its own best, because subtracting two nearly equal numbers destroys digits.
  • The Taylor polynomial of degree n is the sum of f-to-the-k at x0 over k factorial times (x − x0) to the k, and the Taylor series is its limit; at x0 = 0 it is the Maclaurin series, and f = T-infinity means f is analytic.
  • For a polynomial of degree at most n, T_n is not an approximation — it is f, with every later coefficient exactly zero. Verified: T_4 of x^4 at x0 = 1 has max error 7.11e-15.
  • Near x0 the error falls with degree; on a wide interval it need not. For sin + cos the near error falls 5.9e-1 to 2.1e-5 over six degrees while the far error rises 2.41 to 12.26 and then comes back.
  • A Taylor series can fail to converge where the function is perfectly smooth. log(1+x) at 0 converges only for |x| < 1, because the radius is set by the nearest complex singularity.
  • Symmetry changes the local order. For an odd function every even coefficient vanishes, so T_1 is already accurate to h-cubed; predicting h-to-the-(n+1) from the degree alone is wrong for most functions.
  • Never estimate a high derivative by repeated differencing — the k-th difference divides by h to the k, so the 6th coefficient came out as +5.551 instead of -0.001389 and the 8th as -225789 instead of +0.0000248. Jet arithmetic is exact at every order and is forward-mode autodiff.
  • The chain rule is the rule that matters. Everything in §5.2 to §5.6 is the chain rule with more indices.

Next: Partial Differentiation and Gradients — the same definition, one variable at a time.

pch.coffeeTagline

pch.coffeeCta

pch.feedbackHeading

pch.feedbackSubheading