Math for AILoading progress…

Numerical checks

Calculate slopes, use the chain rule and distinguish derivatives from partial derivatives.

Check a derivative with numbers

A formula you derived by hand can be wrong. A cheap test: compare it with a finite difference, a slope computed from nearby function values. Two versions:

  • Forward: (f(x + h) − f(x)) / h. Its error shrinks in proportion to h.
  • Central: (f(x + h) − f(x − h)) / (2h). The errors on the two sides cancel, so the error shrinks in proportion to h², far faster.

These are truncation errors: we cut the limit off at a finite h. It is natural to think a smaller h is always better. The chart below tests that with real double-precision numbers (the same your Python uses) for f = exp at x = 1, where the true derivative is e.

Smaller h is better, until it is not

1e-161e-121e-81e-41e01e-11e-41e-71e-101e-131e-16forward difference errorcentral difference errorh gets smaller →
f = exp, x = 1, true f′(1) = e = 2.7182818284590451
h = 0.0001
forward: 2.7184177470829241   error 1.36e-4
central: 2.7182818329896108   error 4.53e-9
f(x + h) = 2.7185536702337534
f(x)      = 2.7182818284590451
forward numerator = 0.00027184, about 612133257640 units in the last place
central numerator = 0.00054366, about 1224205305014 units in the last place

A double can only change in whole units in the last place. When the numerator is only a handful of those units, the slope can take only a handful of values and the digits are noise.

Both axes are logarithmic. Move k to change h = 10^−k. The curves fall, bottom out and then climb again. Read the digits panel at k = 15 and 16.

The forward error falls as predicted down to about h = 1e-8, the central error down to about 1e-5. Beyond that the second source takes over: floating-point cancellation. Doubles keep about 16 significant digits. When h is tiny, f(x + h) and f(x − h) agree in almost every digit, and subtracting them wipes out the shared digits, leaving a few noisy ones that are then divided by a tiny h. At h = 1e-16 we even get x + h == x, so the numerator is exactly 0. Computed here: the forward error is 6.60e-9 at h = 1e-8 and 1.55e-6 at h = 1e-10, and the central error at h = 1e-15 is 1.68e-1.

print(0.1 + 0.2 == 0.3, 0.1 + 0.2)
import math
x = 1.0
for h in [1e-5, 1e-10, 1e-15, 1e-16]:
    print(h, (math.exp(x + h) - math.exp(x - h)) / (2 * h))
# output:
False 0.30000000000000004
1e-05 2.718281828517632
1e-10 2.7182811557224795
1e-15 2.8865798640254066
1e-16 0.0

Predict first. With f = exp at x = 1, which step gives the better central-difference estimate of e?

What a numerical check can and cannot say

A check at a few points is evidence, not proof. And a kink can fool it: for |x| at 0 the central difference is 0.0, which looks like a perfectly good slope, while the forward difference is 1.0 and the backward difference is −1. Comparing forward and backward catches it.

Chapter context

A derivative measures a local rate of change. It describes what a function does under a very small input change, rather than its average behavior over an arbitrary interval. This local sensitivity is what training algorithms use.

Chapter reference: math, worked example & code

This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.

Math and notation

f′(x)=lim⁡h→0f(x+h)−f(x)h.f'(x)=\lim_{h\to0}\frac{f(x+h)-f(x)}h. ddxf(g(x))=f′(g(x))g′(x),∂∂x(x2+3xy)=2x+3y.\frac{d}{dx}f(g(x))=f'(g(x))g'(x),\quad \frac{\partial}{\partial x}(x^2+3xy)=2x+3y.

For numerical checking, use (f(x+h)−f(x−h))/(2h)(f(x+h)-f(x-h))/(2h) and report a tolerance.

Worked example

Let f(x)=(3x+1)^2. At x=2, the inner value is 7, its derivative is 3, and the outer derivative is 14. Multiplying gives 42. A central difference with h=0.00001 gives approximately the same answer, within numerical error.

Reference code

The following example uses the Python standard library and does not call a remote service.

from math import isclose
f = lambda x: (3*x + 1)**2
x, h = 2, 1e-5
analytic = 6*(3*x + 1)
numeric = (f(x+h)-f(x-h))/(2*h)
assert analytic == 42
assert isclose(numeric, analytic, rel_tol=1e-7)

Python examples are provided for study and local execution; this page does not execute Python.

Common mistakes

A function value is not its derivative. The chain rule multiplies sensitivities, not intermediate values. At a corner such as abs(x) at zero, a two-sided derivative does not exist.