12. Calculus I — Limits, Derivatives, Rates of Change
Level: Intermediate You'll use this for: understanding "rate of change" metrics, and as the prerequisite for all of ML optimization.
The idea
A derivative measures instantaneous rate of change — how fast f(x) is
changing right now, not on average. If f(x) is position, f'(x) is
velocity.
f'(x) = lim(h→0) [f(x+h) - f(x)] / h
Watching that limit converge, numerically
For f(x) = x² at x = 3, plug in shrinking values of h and watch
[f(x+h) - f(x)] / h settle down:
h = 1: [f(3+1) - f(3)] / 1 = [16 - 9] / 1 = 7.0
h = 0.1: [f(3.1) - f(3)] / 0.1 = [9.61 - 9] / 0.1 = 6.1
h = 0.01: [f(3.01) - f(3)] / 0.01 = [9.0601-9]/0.01 = 6.01
h = 0.001: ... = 6.001
As h -> 0, the ratio converges to 6.
The power rule says f'(x) = 2x, so f'(3) = 2×3 = 6 — matching exactly
what the shrinking-h calculation converges to. That's what the "limit"
in the definition means in practice: it's not a mysterious symbol, it's
"keep shrinking h and see what number the ratio approaches."
Common derivative rules
d/dx (x^n) = n·x^(n-1) power rule
d/dx (e^x) = e^x e^x is its own derivative
d/dx (ln x) = 1/x
d/dx (f(x)+g(x)) = f'(x) + g'(x) sum rule
d/dx (f(x)·g(x)) = f'(x)g(x) + f(x)g'(x) product rule
Worked example: marginal cost / rate-of-change intuition
If cost(n) = 0.01·n² + 5n is the cost of serving n requests/sec of
extra compute capacity, cost'(n) = 0.02n + 5 tells you the marginal
cost of the next unit of capacity — not the average cost so far. This
distinction (marginal vs. average) is exactly the reasoning behind capacity
planning decisions like "is it worth adding one more node."
import sympy as sp
n = sp.symbols('n')
cost = 0.01*n**2 + 5*n
marginal = sp.diff(cost, n)
print(marginal) # 0.02*n + 5
print(marginal.subs(n, 100)) # marginal cost at n=100 requests/sec
The derivative, symbol by symbol
f'(x) = lim(h→0) [f(x+h) - f(x)] / h also written df/dx, d/dx f(x)
| Symbol | Say it as | Meaning |
|---|---|---|
f'(x) |
"f prime of x" | the slope of f at the point x |
h |
"h" | a small step to the right of x |
f(x+h) - f(x) |
"rise" | how much the output changed over that step |
… / h |
"rise over run" | the average slope over the step, a secant line |
lim(h→0) |
"the limit as h goes to zero" | the value the average slope settles on as the step shrinks, the tangent line |
df/dx |
"d f d x" (Leibniz notation) | the same thing, written as "a tiny change in f per tiny change in x" |
Units check: if f is bytes and x is seconds, f' is bytes/second.
A derivative always has units of output per input.
Deriving a rule instead of memorizing it
Here's the power rule for f(x) = x², straight from the definition:
[f(x+h) - f(x)] / h = [(x+h)² - x²] / h
= [x² + 2xh + h² - x²] / h
= [2xh + h²] / h
= 2x + h -> as h → 0: f'(x) = 2x
The h² term was "too small to matter", and that's the entire spirit of
calculus: zoom in far enough and every smooth curve looks like a straight
line.
Two more rules you'll need, plus the chain rule (Ch. 13 develops it fully):
d/dx [f(x)/g(x)] = [f'(x)·g(x) - f(x)·g'(x)] / g(x)² quotient rule
d/dx f(g(x)) = f'(g(x)) · g'(x) chain rule
AI in the wild: the sigmoid's derivative and vanishing gradients
The sigmoid squashes any number into a probability (0, 1). It's the output
of every logistic regression and every binary classifier:
σ(x) = 1 / (1 + e^(-x))
Differentiate with the chain rule. The outer function is u⁻¹, the inner is
1 + e^(-x):
σ'(x) = -1·(1 + e^(-x))⁻² · (-e^(-x))
= e^(-x) / (1 + e^(-x))²
= [1/(1 + e^(-x))] · [e^(-x)/(1 + e^(-x))]
= σ(x) · (1 - σ(x))
The derivative is built from the function's own output, so backprop gets it almost for free. It also has a dark side:
x |
σ(x) |
σ'(x) |
|---|---|---|
| 0 | 0.5 | 0.25 (the maximum possible) |
| 4 | 0.982 | 0.018 |
| -4 | 0.018 | 0.018 |
Each sigmoid layer multiplies the gradient by at most 0.25. Through 10
layers that's 0.25¹⁰ ≈ 0.000001, so the early layers barely learn. This
one-line derivative is the reason deep networks switched to ReLU, whose
derivative is exactly 1 for positive inputs (Ch. 21).
Taylor's theorem: every smooth function is secretly a polynomial
Theorem (Taylor). Near a point
a, a smooth function equals its derivatives arranged as a polynomial:f(x) = f(a) + f'(a)(x-a) + f''(a)/2! · (x-a)² + f'''(a)/3! · (x-a)³ + ...
| Symbol | Meaning |
|---|---|
a |
the point you expand around, where you know everything |
x - a |
how far you've moved from it |
f''(a) |
second derivative: the curvature (how fast the slope changes) |
n! |
factorial, n·(n-1)·…·1, which shrinks the higher terms fast |
Keep only the first two terms and you get the linear approximation
f(x) ≈ f(a) + f'(a)(x-a). That's the "zoom in until it's a line" idea as a
formula.
Examples you've already relied on without knowing it:
e^x ≈ 1 + x + x²/2 + x³/6 at x = 0.1: 1.1051667 (true: 1.1051709)
ln(1 + x) ≈ x at x = 0.01: 0.01 (true: 0.00995)
The second one derives Ch. 6's Rule of 72. Money growing at rate r
doubles when (1+r)ᵗ = 2, so t = ln 2 / ln(1+r) ≈ 0.693 / r. That gives
"69.3 divided by the percentage rate", and 72 is used instead because it has
more divisors.
Where Taylor shows up in AI: gradient descent (Ch. 21) is the
first-order Taylor approximation. It assumes the loss is locally a plane and
steps downhill on it. Newton's method and second-order optimizers keep the
f'' term and model the loss as a bowl. The GELU activation used in GPT and
BERT ships with a tanh-based approximation that's tuned to match the true
curve closely and runs faster on GPUs.
Newton's method: square roots in four steps
To solve f(x) = 0, start with a guess, take the tangent line (the
linear approximation above), and jump to where it hits zero:
x_{n+1} = x_n - f(x_n) / f'(x_n)
Example: compute √2, which is the root of f(x) = x² - 2 with f'(x) = 2x.
The update simplifies to x_{n+1} = (x_n + 2/x_n) / 2:
x₀ = 1
x₁ = (1 + 2/1) / 2 = 1.5
x₂ = (1.5 + 2/1.5) / 2 = 1.41666...
x₃ = (1.41667 + 2/1.41667)/2 = 1.4142157
x₄ = 1.41421356237469 (true: 1.41421356237310)
The number of correct digits roughly doubles every step (1, 3, 6, 12). That's called quadratic convergence. Your CPU's square-root and division units, the famous Quake III "fast inverse square root" hack, and the implied-volatility solvers in finance all finish with Newton steps.
Optimization: where the derivative is zero
At a smooth minimum or maximum the tangent is flat, so f'(x) = 0. The
second derivative tells you which one you found:
f'(x*) = 0 and f''(x*) > 0 -> local minimum (curves up, like a bowl)
f'(x*) = 0 and f''(x*) < 0 -> local maximum (curves down, like a hill)
Example: right-sizing a fleet. Each server costs $2/hour, and the
latency penalty to the business falls as you add servers, about 800/n
dollars/hour:
C(n) = 2n + 800/n
C'(n) = 2 - 800/n² = 0 -> n² = 400 -> n* = 20 servers
C''(n) = 1600/n³ > 0 -> minimum ✓
C(10) = $100/h C(20) = $80/h C(40) = $100/h
At the optimum, the marginal cost of one more server equals the marginal
saving from it (2 = 800/n²). Every "find the sweet spot" engineering
trade-off has this shape: cache size vs. hit rate, batch size vs. latency,
replication factor vs. durability.
Networking in the wild: how sensitive is TCP to packet loss?
The Mathis formula approximates steady-state throughput for a loss-based TCP (Reno-style) flow:
throughput ≈ (MSS / RTT) · (C / √p)
| Symbol | Meaning | Example |
|---|---|---|
MSS |
maximum segment size (bytes per packet) | 1460 bytes |
RTT |
round-trip time | 100 ms |
p |
packet-loss probability | 0.0001 (0.01%) |
C |
a constant from the sawtooth geometry (Ch. 25), √(3/2) ≈ 1.22 |
throughput = (1460·8 bits / 0.1 s) · (1.22 / √0.0001)
= 116,800 · 122.5 ≈ 14.3 Mbit/s
Now ask the calculus question: how sensitive is throughput to loss?
d(throughput)/dp = -½ · throughput / p
so a 1% relative increase in loss costs about 0.5% of throughput.
Doubling the loss rate divides throughput by √2 (−29%, down to
10.1 Mbit/s). Going to 1% loss cuts it 10× to 1.4 Mbit/s. And because RTT
sits in the denominator, the same loss rate hurts a transatlantic flow 10×
more than a metro one. These two derivatives are why loss-based congestion
control struggles on long, slightly lossy paths, and why Google built BBR,
which models bandwidth and RTT directly instead of reacting to loss.
Integrals: the accumulated total
If the derivative answers "how fast right now?", the integral answers "how much in total?". It adds up a rate over time, or a density over a range, into an amount.
∫ₐᵇ f(x) dx = lim(n→∞) Σᵢ₌₁ⁿ f(xᵢ) · Δx where Δx = (b - a)/n
| Symbol | Say it as | Meaning |
|---|---|---|
∫ |
"integral" | a stretched "S" for Sum |
a, b |
"from a to b" | the start and end of the range |
f(x) |
"the integrand" | the rate or height being added up |
dx |
"d x" | an infinitely thin slice of the range. Its units multiply in |
Δx |
"delta x" | the width of one finite slice |
Σ f(xᵢ)·Δx |
Riemann sum | chop the area into n rectangles, height × width, and add them up |
Units check: if f is bytes/second and x is seconds, the integral
is bytes. Integration multiplies units by the units of dx, and
differentiation divides them.
Watching the rectangles converge, for ∫₀³ x² dx using midpoint rectangles:
n = 3 rectangles: 8.75
n = 6: 8.9375
n = 30: 8.9975
n = 300: 8.999975 -> converges to exactly 9
Same idea as the derivative's shrinking h: the "limit" just means "keep
slicing thinner and see what the sum approaches."
The Fundamental Theorem of Calculus
The theorem that welded derivatives and integrals into one subject (Newton and Leibniz, 1660s–1680s):
Theorem (FTC). If
F' = f(that is,Fis an antiderivative off), then∫ₐᵇ f(x) dx = F(b) - F(a)And in the other direction:
d/dx ∫ₐˣ f(t) dt = f(x). Accumulating a rate, then asking how fast the total is growing, gives you back the rate.
Integration and differentiation are inverses, so every derivative rule read backwards is an integral rule:
∫ xⁿ dx = xⁿ⁺¹/(n+1) + C (n ≠ -1)
∫ eˣ dx = eˣ + C
∫ 1/x dx = ln|x| + C
∫ e^(-λt) dt = -e^(-λt)/λ + C
(C is the "constant of integration". Constants have zero derivative, so an
antiderivative is only fixed up to a constant, and it cancels in F(b) - F(a).)
Example: ∫₀³ x² dx = [x³/3]₀³ = 27/3 - 0 = 9. That's the 9 the rectangles
were crawling toward, found exactly in one line.
Networking in the wild: rates, totals, and Prometheus
Your monitoring stack is a calculus engine:
| Prometheus function | What it computes | Calculus |
|---|---|---|
rate(bytes_total[5m]) |
bytes/second from an ever-growing counter | derivative of the counter |
increase(bytes_total[1h]) |
bytes transferred in the last hour | integral of the rate |
deriv(queue_depth[10m]) |
how fast a gauge is changing | derivative, by least-squares slope (Ch. 10) |
Example 1, exact: a transfer ramps up linearly, r(t) = 2t Gbit/s, for 10
seconds. Total data:
∫₀¹⁰ 2t dt = [t²]₀¹⁰ = 100 Gbit = 12.5 GB
Its average rate is 10 Gbit/s, half the 20 Gbit/s peak. If you capacity-plan a link off the average, you'll saturate it at the end of every ramp.
Example 2, from samples (the trapezoid rule): you only have
scraped rates, one every 15 s: 100, 140, 180, 160, 120 Mbit/s. Approximate
each 15 s slice as a trapezoid (average of its two ends × width):
total ≈ 15 · [ (100+140)/2 + (140+180)/2 + (180+160)/2 + (160+120)/2 ]
= 15 · [ 120 + 160 + 170 + 140 ]
= 8,850 Mbit ≈ 1,106 MB in one minute
That's how volume-based billing computes "total GB transferred" from sampled
rates. (Transit billed on the 95th percentile uses Ch. 9's percentiles
instead.) A token-bucket rate limiter is the same
integral run live: the bucket holds ∫ refill_rate dt - consumed, capped at the
bucket size.
AI in the wild: probability is integration
For a continuous random variable with density f(x) (Ch. 14), probabilities
are areas:
P(a ≤ X ≤ b) = ∫ₐᵇ f(x) dx ∫₋∞^∞ f(x) dx = 1 E[X] = ∫ x·f(x) dx
Example: the exponential distribution (time to next failure, rate λ):
f(t) = λ·e^(-λt) for t ≥ 0
Total probability: ∫₀^∞ λe^(-λt) dt = [-e^(-λt)]₀^∞ = 0 - (-1) = 1 ✓
P(failure within T) = ∫₀ᵀ λe^(-λt) dt = 1 - e^(-λT)
With MTBF 720 hours (λ = 1/720) and T = 100 h:
1 - e^(-100/720) = 1 - e^(-0.139) ≈ 13%. That's exactly what expon.cdf in
Ch. 14 returns, because the CDF is this integral.
The Gaussian integral, a theorem that explains a constant:
∫₋∞^∞ e^(-x²) dx = √π
(The proof squares the integral, switches to polar coordinates, and the
π falls out of the circle. It's one of the most elegant tricks in
mathematics.) This is why the normal distribution's formula carries that odd
1/√(2π): it's the constant needed to make the total area exactly 1.
ROC AUC is literally an integral. The "area under the ROC curve" used to
score every classifier and intrusion detector (Ch. 26) is
∫₀¹ TPR d(FPR), computed by the trapezoid rule over the curve's points.
For points (0,0), (0.1,0.6), (0.3,0.85), (1,1):
AUC = 0.1·(0+0.6)/2 + 0.2·(0.6+0.85)/2 + 0.7·(0.85+1)/2
= 0.030 + 0.145 + 0.6475 = 0.8225
from scipy.integrate import quad
import numpy as np
print(quad(lambda x: x**2, 0, 3)) # (9.0, ...) area under x²
print(quad(lambda x: np.exp(-x**2), -np.inf, np.inf)) # (1.7724..., ...) = √π
print(np.trapezoid([0, 0.6, 0.85, 1], [0, 0.1, 0.3, 1])) # 0.8225 ROC AUC
Real-life engineering ties
- SWE: understanding "rate of change" dashboards (deploy velocity, error rate acceleration).
- AI: the derivative is literally what gradient descent follows downhill (Ch. 13, 21) — this chapter is the prerequisite for all of neural network training.
- Network: rate of change of queue depth or throughput signals congestion before it becomes an outage (used in AQM/CoDel algorithms, Ch. 25).
- Security: rate-of-change of failed login attempts (acceleration, not just count) is a stronger brute-force signal than a raw threshold.
More real-life examples:
- Cloud cost/capacity dashboards that show "spend rate" and "rate of change of spend" are literally reporting a metric and its derivative — a sudden jump in the derivative is a much earlier warning sign than watching total spend alone.
- Physics engines in games and robotics simulations integrate acceleration to get velocity and velocity to get position every frame — the same derivative chain (position → velocity → acceleration) run continuously at 60+ times a second.
- Newton's method, a numerical technique that uses a function's derivative to iteratively find where it crosses zero, is used inside many optimizers, root-finders, and implied-volatility calculations in finance.
- SRE teams track error-rate velocity (how fast the error rate itself is climbing) as an earlier, more sensitive incident-detection signal than a static error-rate threshold — a derivative-based alert, not a level-based one.
Common mistake
Confusing a rate with a total. "Requests per second is climbing" is a statement about the derivative; "we've served 1M requests today" is a statement about the integral (the accumulated total, Ch. 13). Dashboards that don't clearly label which one you're looking at cause real misdiagnosis during incidents.