32. What f′ and f″ tell you

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

Two signs, four combinations, and between them they describe the shape of any curve. This lesson turns the MVT's consequences into a procedure.

f' decides direction

From §3.4, on an interval:

f' > 0 \implies f \text{ increasing}, \qquad f' < 0 \implies f \text{ decreasing}

Both are MVT corollaries, not definitions.

Critical points are where f'(x) = 0 or f' fails to exist. Both cases matter: |x| has a minimum at 0 where the derivative doesn't exist, and any procedure that only solves f'=0 would miss it.

To find where f increases and decreases: locate the critical points, and check the sign of f' on each interval between them. f' can only change sign at a critical point (by the IVT applied to f', when f' is continuous), so one test value per interval settles it.

The first derivative test

At a critical point c, look at how f' changes sign:

f' goes Conclusion
+ to - local maximum
- to + local minimum
no change neither

"Neither" is a real outcome, not an error. f(x)=x^3 has f'(0)=0 but f'>0 on both sides — the curve pauses and continues. A horizontal tangent is not an extremum.

f'' decides bending

f'' > 0 \implies \text{concave up}, \qquad f''<0 \implies \text{concave down}

An inflection point is where concavity changes. Two conditions, and the second is the one people forget:

  1. f''(c) = 0 or f''(c) doesn't exist, and
  2. f'' actually changes sign at c.

f(x) = x^4 has f''(0)=0 but f'' = 12x^2 \ge 0 everywhere — concave up on both sides, no inflection. f''=0 is necessary, not sufficient, exactly parallel to f'=0 not guaranteeing an extremum.

The second derivative test

At a critical point c with f'(c)=0:

f''(c) Conclusion
>0 local minimum (concave up, sitting in a bowl)
<0 local maximum (concave down, on a dome)
=0 inconclusive — fall back to the first derivative test

Faster than the first test when it works, since it's one evaluation rather than a sign analysis. But the inconclusive case is genuine: x^4 (min), -x^4 (max) and x^3 (neither) all have f'(0)=f''(0)=0, so no amount of squinting at f''(0) can distinguish them.

When f''(c)=0, go back to the first derivative test. It always works.

The four combinations

f' f'' Shape Example
+ + rising, steepening e^x
+ - rising, levelling off \sqrt x, \ln x
- + falling, flattening e^{-x}
- - falling, steepening -e^{x}

The middle two are worth naming: diminishing returns is "f'>0, f''<0" — more input still helps, but each unit helps less. Almost every saturation phenomenon in economics, biology and machine learning has that signature, and recognising it from the two signs is genuinely useful.

Local vs global

The tests above find local extrema. For a global extremum on a closed interval [a,b], the Extreme Value Theorem (§1.8) says one exists, and it must occur at either a critical point or an endpoint.

So the procedure is finite:

  1. Find all critical points in [a,b].
  2. Evaluate f at each, and at a and b.
  3. The largest value is the global max; the smallest is the global min.

No derivative tests needed — you're comparing actual values, not classifying shapes. This is the "closed interval method", and §3.7 uses it constantly.

On an open or unbounded interval there's no such guarantee, and you must check end behaviour separately.

Doing it in Python

Sign analysis, automated:

import sympy as sp

x = sp.Symbol('x')

def analyse(f):
    f1, f2 = sp.diff(f, x), sp.diff(f, x, 2)
    crit = sorted([c for c in sp.solve(f1, x) if c.is_real])
    print(f"f    = {f}")
    print(f"f'   = {sp.factor(f1)}      critical points: {crit}")
    print(f"f''  = {sp.factor(f2)}")
    for c in crit:
        s = f2.subs(x, c)
        if s > 0:
            verdict = "local minimum"
        elif s < 0:
            verdict = "local maximum"
        else:
            left = f1.subs(x, c - sp.Rational(1, 100))
            right = f1.subs(x, c + sp.Rational(1, 100))
            verdict = ("neither (no sign change)" if left * right > 0
                       else "extremum by first-derivative test")
        print(f"  x={c}: f={f.subs(x,c)}, f''={s} -> {verdict}")
    print()

analyse(x**3 - 3*x)
analyse(x**4)
analyse(x**3)

The inconclusive case, three functions that f'' cannot tell apart:

import sympy as sp

x = sp.Symbol('x')

for f in (x**4, -x**4, x**3):
    f1, f2 = sp.diff(f, x), sp.diff(f, x, 2)
    print(f"f = {str(f):<8} f'(0) = {f1.subs(x,0)}  f''(0) = {f2.subs(x,0)}")

print("\nidentical at 0, yet: x^4 has a minimum, -x^4 a maximum, x^3 neither.")
print("the second derivative test is silent; the first-derivative test is not:")

for f in (x**4, -x**4, x**3):
    f1 = sp.diff(f, x)
    l, r = f1.subs(x, -sp.Rational(1,10)), f1.subs(x, sp.Rational(1,10))
    print(f"  {str(f):<8} f' goes {'+' if l>0 else '-'} to {'+' if r>0 else '-'}")

f''=0 without an inflection:

import sympy as sp

x = sp.Symbol('x')

for f in (x**3, x**4):
    f2 = sp.diff(f, x, 2)
    l, r = f2.subs(x, -1), f2.subs(x, 1)
    changes = (l > 0) != (r > 0)
    print(f"f = {str(f):<6} f'' = {str(f2):<8} at x=-1: {int(l):>4}, "
          f"at x=1: {int(r):>4}  inflection at 0? {changes}")

print("\nboth have f''(0) = 0. only x^3 changes concavity, so only it inflects.")

The closed-interval method:

import sympy as sp

x = sp.Symbol('x')
f = x**3 - 3*x
a, b = -2, 3

crit = [c for c in sp.solve(sp.diff(f, x), x) if c.is_real and a <= c <= b]
candidates = sorted(set(crit + [a, b]))

print(f"f = {f} on [{a}, {b}]")
print(f"candidates (critical points + endpoints): {candidates}\n")
for c in candidates:
    print(f"  f({c}) = {f.subs(x, c)}")

values = {c: f.subs(x, c) for c in candidates}
print(f"\nglobal max {max(values.values())} at x={max(values, key=values.get)}")
print(f"global min {min(values.values())} at x={min(values, key=values.get)}")
print("\nnote the max is at an ENDPOINT, not a critical point")

Worked example

Analyse f(x) = x^4 - 4x^3 completely.

f'(x) = 4x^3 - 12x^2 = 4x^2(x-3)

f''(x) = 12x^2 - 24x = 12x(x-2)

Critical points: f'=0 at x=0 (double root) and x=3.

Sign of f'. The factor 4x^2 \ge 0 always, so the sign is entirely (x-3)'s:

  • x < 3: f' < 0, decreasing (including through x=0)
  • x > 3: f' > 0, increasing

Classification.

At x=3: f''(3) = 108-72 = 36 > 0local minimum, f(3) = 81-108 = -27.

At x=0: f''(0) = 0 → inconclusive. Fall back to the first derivative test: f' is negative on both sides (the x^2 factor never lets it change sign), so x=0 is neither a max nor a min. The curve has a horizontal tangent and keeps descending — a saddle in one dimension.

Concavity. f''=12x(x-2) is zero at x=0 and x=2:

  • x<0: both factors negative → f''>0, concave up
  • 0<x<2: signs differ → f''<0, concave down
  • x>2: both positive → f''>0, concave up

Both are genuine inflection points, since concavity changes at each.

The picture. Falls from +\infty, concave up until x=0; flattens momentarily at the origin without stopping; continues down while concave down; inflects again at x=2; bottoms out at (3,-27); rises to +\infty.

The instructive bit is x=0: a critical point, an inflection point, and not an extremum, all at once. It's the case that shows why the second derivative test needs a fallback, and why f''=0 has to be checked for a sign change.

Your turn

1. Find and classify the critical points of f(x)=x^3-6x^2+9x+1.

2. Find the inflection points of f(x)=x^4-6x^2.

3. Find the global extrema of f(x)=x^3-3x on [-2,3].

4. Why can't the second derivative test classify f(x)=x^4 at x=0?

Solutions

1. f'(x) = 3x^2-12x+9 = 3(x-1)(x-3), zero at x=1 and x=3.

f''(x) = 6x-12.

  • f''(1) = -6 < 0local maximum, f(1) = 1-6+9+1 = 5
  • f''(3) = 6 > 0local minimum, f(3) = 27-54+27+1 = 1

Consistent with the shape of a cubic with positive leading coefficient: up, over the hump, down into the dip, up again.

2. f' = 4x^3-12x, f'' = 12x^2-12 = 12(x^2-1), zero at x=\pm1.

Sign check: f''(0) = -12 < 0 and f''(\pm2) = 36 > 0. Concavity changes at both, so both are genuine inflection points:

\boxed{(-1, -5) \text{ and } (1,-5)}

(since f(\pm1) = 1-6 = -5).

3. Closed interval, so use the closed-interval method.

f' = 3x^2-3 = 3(x-1)(x+1), critical at x=\pm1, both inside [-2,3].

Evaluate at critical points and endpoints:

x -2 -1 1 3
f(x) -2 2 -2 18

\text{global max} = \boxed{18 \text{ at } x=3}, \qquad \text{global min} = \boxed{-2 \text{ at } x=-2 \text{ and } x=1}

Two things worth noticing. The global maximum is at an endpoint, not at the local maximum x=-1 — which is exactly why endpoints go in the candidate list. And the global minimum is attained at two points; the EVT guarantees existence, never uniqueness.

4. Because f''(0) = 12(0)^2 = 0, and the test says nothing when f''(c)=0.

The reason it can't say anything: the test works by treating f as approximately a parabola near c, with f''(c) as the parabola's opening direction. When f''(c)=0 there is no parabola — the function is flatter than quadratic at that point, and the behaviour is decided by higher-order terms the test never looks at.

For x^4 the deciding term is the quartic one, positive on both sides, so it's a minimum. The first derivative test sees this immediately: f' = 4x^3 goes from negative to positive. ✓

Check yourself in code

Classify the critical points of f(x) = x^4 - 4x^3, falling back to the first derivative test when f''=0.

Print f', f'', the critical points, and for each one its f'' value and the verdict. Use sp.solve for the critical points, and for the fallback compare f' just left and right of the point.

Print exactly this:

f'  = 4*x**3 - 12*x**2
f'' = 12*x*(x - 2)
critical points: [0, 3]
x=0  f''=0  not an extremum
x=3  f''=36  local minimum
import sympy as sp

x = sp.Symbol('x')
f = x**4 - 4*x**3
f1, f2 = sp.diff(f, x), sp.diff(f, x, 2)

print(f"f'  = {f1}")
print(f"f'' = {sp.factor(f2)}")
crit = sorted(sp.solve(f1, x))
print(f"critical points: {crit}")

for c in crit:
    # second-derivative test, with the first-derivative test as fallback
    print(f"x={c}  ...")
import sympy as sp

x = sp.Symbol('x')
f = x**4 - 4*x**3
f1, f2 = sp.diff(f, x), sp.diff(f, x, 2)

print(f"f'  = {f1}")
print(f"f'' = {sp.factor(f2)}")
crit = sorted(sp.solve(f1, x))
print(f"critical points: {crit}")

for c in crit:
    s = f2.subs(x, c)
    if s > 0:
        verdict = "local minimum"
    elif s < 0:
        verdict = "local maximum"
    else:
        left = f1.subs(x, c - sp.Rational(1, 10))
        right = f1.subs(x, c + sp.Rational(1, 10))
        verdict = "not an extremum" if left * right > 0 else "extremum (sign change)"
    print(f"x={c}  f''={s}  {verdict}")

f' gives direction and f'' gives bending, and their signs together pin down the shape. Critical points are where f' is zero or undefined; the first derivative test classifies them by sign change and always works, while the second derivative test is faster but goes silent when f''(c)=0. Inflection points need f'' to change sign, not merely vanish. And for a global extremum on a closed interval, skip the tests entirely — evaluate at every critical point and both endpoints, and compare.

Next: assembling all of it into a complete picture of a curve.