A box from a sheet of card
A cooperative of packaging makers in Oaxaca folds open boxes from rectangular sheets of card, cm by cm. From each corner they cut a square of side cm and fold up the sides. The box is cm tall, with a base of by cm, so its volume is
A customer wants boxes holding exactly one litre, . Trying gives . Success! But is the only size that works? A shorter, wider box might use the card differently.
We need to solve , an equation of degree three. Guessing found one solution. This lesson shows how one known solution splits the problem into a smaller one, and how many solutions there can possibly be. (We finish the box at the end of the worked examples.)
Polynomials are like numbers in base x
The number means . The expression is the same pattern with the base replaced by a letter, and putting gives back .
This is more than a coincidence of notation. You add polynomials by collecting like powers, as you add numbers column by column. You multiply them with the same grid as long multiplication, only without carrying: a coefficient may grow as large as it likes. And you divide them by a long-division process that works one leading term at a time. Polynomials are the integers of algebra, and the parallel runs deep — both have a division algorithm with remainders, both have "primes" (irreducible polynomials), and both factorise uniquely into them (up to signs or constant factors).
Definitions
Definition— polynomial
A polynomial in with real coefficients is an expression
where is a whole number and are real numbers, the coefficients. Two polynomials are equal when their coefficients of each power of agree.
Definition— degree, leading coefficient
If , then is the degree of , written , and is its leading coefficient. A polynomial whose leading coefficient is is called monic. The zero polynomial (all coefficients ) has no degree: by convention we leave undefined (some books write ).
Definition— root
A number is a root (or zero) of if . Here means: substitute for and calculate.
Degree- polynomials are the non-zero constants; degrees are called linear, quadratic, cubic and quartic. Expressions such as , or are not polynomials: only whole-number powers of are allowed.
Theorem— Lemma (degree of a product)
If and are non-zero polynomials with real coefficients, then and . Also when .
Proof
Let the leading terms be and with . When we multiply out , the only way to make is ; every other product of terms has a smaller power. So the coefficient of in is , which is non-zero because a product of two non-zero real numbers is non-zero. No higher power appears. For the sum, no power above occurs in either polynomial.
∎
The sum can have a smaller degree than both summands: .
Worked examples
Example— Special products
These identities hold for all numbers (expand the right-hand sides to check):
Read from right to left they multiply; read from left to right they factorise. For example , and .
Example— Factorising by grouping
So the roots are : a product is zero exactly when one of its factors is.
Example— Non-examples: what does not factorise
- has no real roots ( for every real ), so it has no factor with real. It does factorise over the complex numbers: .
- factorises with real coefficients but not with rational ones, because is irrational (see real numbers).
Whether a polynomial factorises depends on which numbers you allow as coefficients.
Example— Long division
Divide by . At each step, divide the leading term of what is left by the leading term of :
- . Subtract : left with .
- . Subtract : left with .
- . Subtract : left with .
The leftover has degree , so we stop:
The quotient is and the remainder is .
Example— Synthetic division by x − a
Dividing by is so common that it has a shortcut, synthetic division (Horner's or Ruffini's rule). Divide by : write the coefficients, bring down the first, then repeatedly multiply by and add:
| sum |
The bottom row gives the quotient and the remainder . So .
Example— Finishing the box
Back to the box: , and we know is a root. Synthetic division by gives
The quadratic factor has roots , about and . A cut of cm is impossible on a cm side (we need ), but cm works: a shorter, wider one-litre box. The cooperative has two designs to choose from — and, as we will prove, a cubic can never have more than three roots, so there are no others hiding.
Division, remainders and roots
Theorem— Division algorithm
Let and be polynomials with real (or rational) coefficients, . Then there are unique polynomials (the quotient) and (the remainder) with
Proof
Existence, by strong induction on the degree of . If or , take and . Otherwise let have leading term and have leading term , with . The polynomial
has the terms cancelled, so or . By the induction hypothesis with or . Then . (This is exactly one step of long division.)
Uniqueness. Suppose , both remainders being or of degree less than . Then . If , the lemma on products says the left side has degree . But the right side is or has degree less than . That is impossible, so , and then .
∎
We needed to divide by the leading coefficient . That is why the theorem is stated for rational or real coefficients. With integer coefficients it still works when is monic, such as .
Theorem— Remainder theorem
The remainder when is divided by is the number . That is, for some polynomial .
Proof
First proof. By the division algorithm, where is or has degree less than , so is a constant. Substituting gives .
Second proof, without the division algorithm. For each ,
as you can check by expanding (the middle terms cancel in pairs). If then
and divides every term, so it divides .
∎
Theorem— Factor theorem
is a factor of if and only if .
Proof
If , then . Conversely, if , the remainder theorem gives .
∎
Theorem— Root bound
A non-zero polynomial of degree with real (or complex) coefficients has at most roots.
Proof
Induction on . A polynomial of degree is a non-zero constant and has no roots. Now let and assume the statement for degree . If has no roots, we are done. Otherwise pick a root . By the factor theorem , and by the lemma .
Let be any root of other than . Then . Since and a product of real (or complex) numbers is zero only if a factor is zero, . So every root of is either or a root of . By the induction hypothesis has at most roots, so has at most .
∎
Theorem— Corollary (identity theorem)
If two polynomials and , each zero or of degree at most , take the same values at different numbers, then .
Proof
If , then is a non-zero polynomial of degree at most with at least roots, contradicting the root bound.
∎
So a polynomial identity of degree can be proved by checking values. That is unusual: in general, checking examples refutes but never proves. Here the root bound turns finitely many checks into a proof.
Theorem— Rational root test
Let have integer coefficients, with and . If a fraction in lowest terms is a root of , then divides and divides .
Proof
Substitute and multiply by :
Every term except the last contains the factor , so divides . Since and have no common prime factor, shares none with , and so divides (by unique factorisation; see divisibility). Similarly every term except the first contains , so divides and hence divides .
∎
For the only candidates are . Testing them finds . For the candidates all fail, which proves that is irrational.
Note
Over the complex numbers much more is true. The fundamental theorem of algebra (first proved in the late 18th and early 19th centuries; see complex numbers) says every non-constant polynomial has a complex root. Applying the factor theorem again and again, every polynomial of degree splits into linear factors over . So it has exactly complex roots when each is counted as often as its factor appears. We do not prove it here: every proof needs some analysis or topology — at the very least, the completeness of the real numbers.
The theorems, checked by Lean
Lean's library Mathlib has a type of polynomials, written R[X] for coefficients in R. In it, C a is the constant polynomial , p.eval a is and p.natDegree is the degree. The special products are identities in any commutative ring, and the tactic ring checks them by expanding both sides:
/-- **Difference of two squares:** `a² − b² = (a − b)(a + b)` in every commutative ring.
`ring` expands both sides and compares them — exactly the check you would do by hand. -/
theorem diff_of_squares {R : Type*} [CommRing R] (a b : R) :
a ^ 2 - b ^ 2 = (a - b) * (a + b) := by
ring/-- **Sum and difference of two cubes:** `a³ + b³ = (a + b)(a² − ab + b²)` and
`a³ − b³ = (a − b)(a² + ab + b²)`. -/
theorem sum_and_diff_of_cubes {R : Type*} [CommRing R] (a b : R) :
a ^ 3 + b ^ 3 = (a + b) * (a ^ 2 - a * b + b ^ 2) ∧
a ^ 3 - b ^ 3 = (a - b) * (a ^ 2 + a * b + b ^ 2) := by
constructor <;> ringThe second proof of the remainder theorem has two steps. First, divides , proved by induction from :
/-- **`x − a` divides `xⁿ − aⁿ`**, by induction on `n`, using the lesson's identity
`xⁿ⁺¹ − aⁿ⁺¹ = x(xⁿ − aⁿ) + aⁿ(x − a)`. (Mathlib: `sub_dvd_pow_sub_pow`.) -/
theorem sub_dvd_pow_sub_pow' {R : Type*} [CommRing R] (x a : R) (n : ℕ) :
x - a ∣ x ^ n - a ^ n := by
induction n with
| zero => simp
| succ n ih =>
obtain ⟨q, hq⟩ := ih
refine ⟨x * q + a ^ n, ?_⟩
calc x ^ (n + 1) - a ^ (n + 1) = x * (x ^ n - a ^ n) + a ^ n * (x - a) := by ring
_ = x * ((x - a) * q) + a ^ n * (x - a) := by rw [hq]
_ = (x - a) * (x * q + a ^ n) := by ringThen is built from single terms by adding, and each term is handled by the lemma:
/-- **Remainder theorem:** `X − a` divides `p − p(a)`, so `p = (X − a)·q + p(a)`.
As in the lesson: `p − p(a)` is a sum of terms `c (Xᵏ − aᵏ)`, and `X − a` divides each of them
(`sub_dvd_pow_sub_pow'`). Lean's induction principle `Polynomial.induction_on'` builds every
polynomial from single terms `c Xᵏ` by addition, so we check those two cases. -/
theorem remainder_theorem {R : Type*} [CommRing R] (p : R[X]) (a : R) :
X - C a ∣ p - C (p.eval a) := by
induction p using Polynomial.induction_on' with
| add p q hp hq =>
have h : p + q - C ((p + q).eval a) = (p - C (p.eval a)) + (q - C (q.eval a)) := by
rw [eval_add, C_add]; ring
rw [h]
exact dvd_add hp hq
| monomial n c =>
have h : monomial n c - C ((monomial n c).eval a) = C c * (X ^ n - (C a) ^ n) := by
rw [eval_monomial, ← C_mul_X_pow_eq_monomial, C_mul, C_pow]; ring
rw [h]
exact dvd_mul_of_dvd_right (sub_dvd_pow_sub_pow' X (C a) n) (C c)Mathlib states the same theorem as "the remainder on dividing by the monic polynomial is the constant ". Our version above is proved here, from more basic facts; this one only applies a library theorem:
/-- **Remainder theorem, Mathlib's form:** the remainder on dividing `p` by the monic polynomial
`X − a` is the constant `p(a)`. This applies `Polynomial.modByMonic_X_sub_C_eq_C_eval`. -/
theorem remainder_theorem_library {R : Type*} [CommRing R] (p : R[X]) (a : R) :
p %ₘ (X - C a) = C (p.eval a) :=
modByMonic_X_sub_C_eq_C_eval p a/-- **Factor theorem:** `X − a` divides `p` exactly when `p(a) = 0`.
(→) If `p = (X − a)·q` then `p(a) = (a − a)·q(a) = 0`.
(←) If `p(a) = 0`, the remainder theorem says `X − a` divides `p − 0 = p`.
(Mathlib: `Polynomial.dvd_iff_isRoot`.) -/
theorem factor_theorem {R : Type*} [CommRing R] (p : R[X]) (a : R) :
X - C a ∣ p ↔ p.eval a = 0 := by
constructor
· rintro ⟨q, rfl⟩
simp
· intro h
have := remainder_theorem p a
rwa [h, C_0, sub_zero] at thisFor the division algorithm we take existence from Mathlib (over any field, such as or ) and prove uniqueness with the degree argument of the lesson:
/-- **Division algorithm (existence)** over a field such as `ℚ` or `ℝ`: for `d ≠ 0` there are
`q` and `r` with `p = q·d + r` and `deg r < deg d` (Mathlib's `degree` of the zero polynomial is
`⊥`, below every natural number, so `r = 0` is included). This applies
`EuclideanDomain.div_add_mod` and `Polynomial.degree_mod_lt`. -/
theorem division_exists {K : Type*} [Field K] (p d : K[X]) (hd : d ≠ 0) :
∃ q r : K[X], p = q * d + r ∧ r.degree < d.degree :=
⟨p / d, p % d, by rw [mul_comm]; exact (EuclideanDomain.div_add_mod p d).symm,
degree_mod_lt p hd⟩/-- **Division algorithm (uniqueness):** quotient and remainder are unique.
If `q₁d + r₁ = q₂d + r₂` with both remainders of degree `< deg d`, then
`(q₁ − q₂)·d = r₂ − r₁`. If `q₁ ≠ q₂`, the left side has degree `≥ deg d`, but the right side has
degree `< deg d` — impossible. So `q₁ = q₂`, and then `r₁ = r₂`. -/
theorem division_unique {K : Type*} [Field K] {d q₁ r₁ q₂ r₂ : K[X]}
(h : q₁ * d + r₁ = q₂ * d + r₂) (h₁ : r₁.degree < d.degree) (h₂ : r₂.degree < d.degree) :
q₁ = q₂ ∧ r₁ = r₂ := by
have key : (q₁ - q₂) * d = r₂ - r₁ := by linear_combination h
have hq : q₁ = q₂ := by
by_contra hne
have hd : d ≠ 0 := by
rintro rfl
simp at h₁
have hsub : q₁ - q₂ ≠ 0 := sub_ne_zero.mpr hne
-- the degree of the left side is at least `deg d`
have hle : d.degree ≤ ((q₁ - q₂) * d).degree := by
rw [degree_mul, add_comm]
exact le_add_of_nonneg_right (zero_le_degree_iff.mpr hsub)
-- the degree of the right side is less than `deg d`
have hlt : (r₂ - r₁).degree < d.degree :=
lt_of_le_of_lt (degree_sub_le r₂ r₁) (max_lt h₂ h₁)
rw [key] at hle
exact absurd (lt_of_le_of_lt hle hlt) (lt_irrefl _)
subst hq
exact ⟨rfl, by linear_combination h⟩The rational root test is formalised for cubics, with the general statement in Mathlib named in the docstring. The hypothesis h is the equation after multiplying by , just as in the proof:
/-- **Rational root theorem (degree 3).** Suppose the fraction `p/q` in lowest terms is a root of
`a₃x³ + a₂x² + a₁x + a₀` with integer coefficients. Multiplying by `q³` gives the hypothesis `h`.
Then `p` divides the constant term `a₀` and `q` divides the leading coefficient `a₃`.
Proof: `a₀q³ = −p(a₃p² + a₂pq + a₁q²)` is a multiple of `p`, and `p` shares no factor with
`q³`, so `p ∣ a₀`; symmetrically for `q`. (The general degree-`n` statement is Mathlib's
`num_dvd_of_is_root` and `den_dvd_of_is_root`.) -/
theorem rational_root_cubic {a₀ a₁ a₂ a₃ p q : ℤ} (hpq : IsCoprime p q)
(h : a₃ * p ^ 3 + a₂ * p ^ 2 * q + a₁ * p * q ^ 2 + a₀ * q ^ 3 = 0) :
p ∣ a₀ ∧ q ∣ a₃ := by
constructor
· have h1 : p ∣ a₀ * q ^ 3 :=
⟨-(a₃ * p ^ 2 + a₂ * p * q + a₁ * q ^ 2), by linear_combination h⟩
exact hpq.pow_right.dvd_of_dvd_mul_right h1
· have h2 : q ∣ a₃ * p ^ 3 :=
⟨-(a₂ * p ^ 2 + a₁ * p * q + a₀ * q ^ 2), by linear_combination h⟩
exact hpq.symm.pow_right.dvd_of_dvd_mul_right h2The root bound is proved over any integral domain, a number system with the zero-product property, which covers , , and at once. The proof is the lesson's induction, organised by adding one root at a time:
/-- **A non-zero polynomial of degree `n` has at most `n` roots** (over any integral domain:
`ℤ`, `ℚ`, `ℝ`, `ℂ`, …). If `S` is a finite set of roots of `p ≠ 0`, then `|S| ≤ deg p`.
Proof by induction on `S`, as in the lesson: if `a` is a root, the factor theorem gives
`p = (X − a)·q` with `deg q = deg p − 1`; every *other* root `b` of `p` satisfies
`(b − a)·q(b) = 0` with `b − a ≠ 0`, so `q(b) = 0` (zero-product property); induction on `q`
finishes. -/
theorem card_roots_le_natDegree {R : Type*} [CommRing R] [IsDomain R] [DecidableEq R]
(S : Finset R) : ∀ p : R[X], p ≠ 0 → (∀ a ∈ S, p.eval a = 0) → S.card ≤ p.natDegree := by
induction S using Finset.induction_on with
| empty => intro p _ _; simp
| insert a S haS ih =>
intro p hp hroots
obtain ⟨q, rfl⟩ := (factor_theorem p a).mpr (hroots a (Finset.mem_insert_self a S))
have hq : q ≠ 0 := by
rintro rfl
simp at hp
-- every other root of `p` is a root of `q`
have hS : ∀ b ∈ S, q.eval b = 0 := by
intro b hb
have hb' := hroots b (Finset.mem_insert_of_mem hb)
rw [eval_mul, eval_sub, eval_X, eval_C] at hb'
have hba : b - a ≠ 0 := sub_ne_zero.mpr (fun h => haS (h ▸ hb))
exact (mul_eq_zero.mp hb').resolve_left hba
have hdeg : ((X - C a) * q).natDegree = q.natDegree + 1 := by
rw [natDegree_mul (X_sub_C_ne_zero a) hq, natDegree_X_sub_C, add_comm]
rw [Finset.card_insert_of_notMem haS, hdeg]
exact Nat.succ_le_succ (ih q hq hS)/-- **The root bound, Mathlib's form:** the multiset of roots of `p` (each root counted with
multiplicity) has at most `deg p` elements. This applies `Polynomial.card_roots'`. -/
theorem card_roots_library {R : Type*} [CommRing R] [IsDomain R] (p : R[X]) :
Multiset.card p.roots ≤ p.natDegree :=
card_roots' p/-- **Identity theorem:** if two polynomials of degree `≤ n` agree at `n + 1` different points,
they are the same polynomial. Their difference has degree `≤ n` and at least `n + 1` roots, so by
`card_roots_le_natDegree` it must be the zero polynomial. -/
theorem eq_of_agree {R : Type*} [CommRing R] [IsDomain R] [DecidableEq R] {p q : R[X]} {n : ℕ}
(hp : p.natDegree ≤ n) (hq : q.natDegree ≤ n) (S : Finset R) (hS : n + 1 ≤ S.card)
(hagree : ∀ a ∈ S, p.eval a = q.eval a) : p = q := by
by_contra hne
have hsub : p - q ≠ 0 := sub_ne_zero.mpr hne
have hroots : ∀ a ∈ S, (p - q).eval a = 0 := by
intro a ha
rw [eval_sub, hagree a ha, sub_self]
have h1 := card_roots_le_natDegree S (p - q) hsub hroots
have h2 : (p - q).natDegree ≤ n := (natDegree_sub_le p q).trans (max_le hp hq)
omegaFinally, the zero-product property really is needed. In ZMod 8, the integers modulo 8, the root bound fails, while modulo the prime it holds:
/-- **Why the zero-product property matters.** In the integers modulo 8 (where `2 · 4 = 0` with
neither factor zero) the degree-2 polynomial `x² − 1` has **four** roots: `1, 3, 5, 7`.
`decide` checks all eight residues. -/
theorem four_roots_mod_eight :
∀ x : ZMod 8, x ^ 2 - 1 = 0 ↔ x = 1 ∨ x = 3 ∨ x = 5 ∨ x = 7 := by
decide/-- **Contrast:** modulo the prime 7 there are no zero divisors, and `x² − 1` has only the two
roots `1` and `6 = −1`, as the root bound predicts. `decide` checks all seven residues. -/
theorem two_roots_mod_seven : ∀ x : ZMod 7, x ^ 2 - 1 = 0 ↔ x = 1 ∨ x = 6 := by
decideDividing exactly, and counting roots in clock arithmetic
"""Synthetic division, the remainder theorem and the rational root test.
Divides polynomials by x - a with exact rational arithmetic (synthetic
division, i.e. Horner's scheme), checks on thousands of random cases that the
remainder equals p(a), and uses the rational root test to factorise a cubic
completely. The random check is experimental evidence; the lesson's proof of
the remainder theorem covers every polynomial and every number a.
"""
import random
from fractions import Fraction
def synthetic_division(coeffs, a):
"""Divide p by (x - a). ``coeffs`` lists p's coefficients, highest first.
Returns (quotient coefficients, remainder), computed exactly.
"""
if not coeffs:
raise ValueError("p must have at least one coefficient")
running = []
value = Fraction(0)
for c in coeffs:
value = value * a + c
running.append(value)
return running[:-1], running[-1]
def evaluate(coeffs, x):
"""p(x) computed term by term (not by Horner), for an independent check."""
n = len(coeffs) - 1
return sum(Fraction(c) * Fraction(x) ** (n - i) for i, c in enumerate(coeffs))
def divisors(n):
"""Positive divisors of the non-zero integer n."""
n = abs(n)
if n == 0:
raise ValueError("0 has infinitely many divisors")
return [d for d in range(1, n + 1) if n % d == 0]
def rational_root_candidates(coeffs):
"""All +-p/q with p | constant term and q | leading coefficient (sorted)."""
lead, const = coeffs[0], coeffs[-1]
cands = {s * Fraction(p, q) for p in divisors(const)
for q in divisors(lead) for s in (1, -1)}
return sorted(cands)
def rational_roots(coeffs):
"""The candidates of the rational root test that really are roots."""
return [r for r in rational_root_candidates(coeffs)
if evaluate(coeffs, r) == 0]
def show(coeffs):
"""Readable form of a polynomial, e.g. 2x^2 + 3x - 2."""
n = len(coeffs) - 1
terms = []
for i, c in enumerate(coeffs):
if c == 0:
continue
k = n - i
mag = abs(c)
body = "" if (mag == 1 and k > 0) else str(mag)
body += "" if k == 0 else ("x" if k == 1 else f"x^{k}")
terms.append(("- " if c < 0 else "+ ") + body)
if not terms:
return "0"
text = " ".join(terms)
return text[2:] if text.startswith("+ ") else "-" + text[2:]
def random_check(trials, seed=2024):
"""Compare the synthetic-division remainder with p(a) on random cases.
Returns the number of disagreements (the theorem predicts 0).
"""
rng = random.Random(seed)
failures = 0
for _ in range(trials):
coeffs = [rng.randint(-9, 9) for _ in range(rng.randint(1, 7))]
a = Fraction(rng.randint(-20, 20), rng.randint(1, 6))
_, remainder = synthetic_division(coeffs, a)
failures += remainder != evaluate(coeffs, a)
return failures
def main():
p = [2, -3, -11, 6]
print(f"p(x) = {show(p)}")
q, r = synthetic_division(p, 3)
print(f"divide by x - 3: quotient {show(q)}, remainder {r}")
print(f"p(3) = {evaluate(p, 3)}, so x - 3 is a factor (factor theorem)")
cands = rational_root_candidates(p)
print(f"rational root test: {len(cands)} candidates +-p/q,")
print(" p | 6 and q | 2:", ", ".join(str(c) for c in cands if c > 0))
roots = rational_roots(p)
print(" roots found:", ", ".join(str(x) for x in roots))
print(" so p(x) = (x + 2)(2x - 1)(x - 3)")
print()
_, r2 = synthetic_division([1, 0, 0, -2], Fraction(5, 4))
print(f"x^3 - 2 divided by x - 5/4: remainder {r2} = p(5/4)")
found = rational_roots([1, 0, 0, -2])
print(f"x^3 - 2: candidates +-1, +-2; rational roots: {found or 'none'}")
print(" so the cube root of 2 is irrational")
trials = 2000
print(f"random check, {trials} polynomials and points a:"
f" {random_check(trials)} disagreements")
print()
print("Epistemic status: the worked divisions and the root search are exact")
print("computations with fractions. The random check is experimental evidence")
print("for 2,000 cases only; the remainder theorem's proof in the lesson is")
print("what guarantees remainder = p(a) for every polynomial and every a.")
if __name__ == "__main__":
main()Two thousand agreements are evidence, not proof: they cover two thousand cases out of infinitely many. The theorem covers them all. Notice the last search, though. For the computer tries the only possible rational roots, and all four fail. Because the rational root test is a theorem, that finite search is a complete proof that is irrational.
Next, the root bound in clock arithmetic. Where does it fail, and where does an exhaustive search find no failure at all?
"""When can a polynomial have more roots than its degree?
Over the real or complex numbers a non-zero polynomial of degree n has at most
n roots. The proof uses the zero-product property: if uv = 0 then u = 0 or
v = 0. In clock arithmetic modulo n that property fails when n is composite,
and so does the root bound. This experiment counts roots of x^2 - 1 modulo n
and checks the bound exhaustively for every polynomial of degree at most 3
modulo the primes 2, 3, 5 and 7.
"""
from itertools import product
def roots_mod(coeffs, n):
"""Residues x in 0..n-1 with p(x) = 0 mod n; coefficients highest first."""
found = []
for x in range(n):
value = 0
for c in coeffs:
value = (value * x + c) % n
if value == 0:
found.append(x)
return found
def degree_mod(coeffs, p):
"""Degree of the polynomial modulo p, or None for the zero polynomial."""
for i, c in enumerate(coeffs):
if c % p:
return len(coeffs) - 1 - i
return None
def bound_violations(p, max_degree):
"""Count non-zero polynomials of degree <= max_degree mod p with more
roots than their degree. Returns (number checked, violations)."""
checked = violations = 0
for coeffs in product(range(p), repeat=max_degree + 1):
d = degree_mod(coeffs, p)
if d is None:
continue
checked += 1
violations += len(roots_mod(coeffs, p)) > d
return checked, violations
def zero_divisors(n):
"""Pairs (u, v) with 0 < u <= v < n and u*v = 0 mod n."""
return [(u, v) for u in range(1, n) for v in range(u, n) if u * v % n == 0]
def main():
print("roots of x^2 - 1 modulo n (degree 2, so at most 2 if the bound held):")
row = []
for n in range(2, 25):
row.append(f"{n}:{len(roots_mod([1, 0, -1], n))}")
if len(row) == 8:
print(" " + " ".join(row))
row = []
if row:
print(" " + " ".join(row))
print(" modulo 8 the roots are", roots_mod([1, 0, -1], 8),
"- four roots of a quadratic")
print(" why: (x - 1)(x + 1) = 0 mod 8 with neither factor 0,")
print(" e.g. x = 3 gives 2 * 4 = 8; zero divisors mod 8:", zero_divisors(8))
print()
print("every non-zero polynomial of degree <= 3 modulo a prime p:")
for p in (2, 3, 5, 7):
checked, bad = bound_violations(p, 3)
print(f" p = {p}: {checked:5d} polynomials, {bad} with too many roots")
print()
print("Epistemic status: every count above is an exact, exhaustive check of")
print("finitely many cases, and the modulo-8 example is a genuine")
print("counterexample showing the zero-product hypothesis is needed. The")
print("checks prove nothing about higher degrees or other primes; the")
print("lesson's proof covers every integral domain.")
if __name__ == "__main__":
main()Modulo a composite number such as , or , a quadratic can have more than two roots. Modulo a prime there are no zero divisors, and the exhaustive search finds no failure among all the polynomials of degree at most , exactly as the proof predicts.
Explore: roots and factors
Move the sliders , and . The cubic crosses the -axis exactly at its three roots. What happens when two roots meet? (The graph touches the axis instead of crossing: a repeated factor.) What does making negative do?
A cubic with chosen roots
Move the sliders and trace along the curves to read off values.
- y = a(x − r)(x − s)(x − t)
- y = a(x − r)(x − s)(x − t): y = −1.5
Now change in . For there are three real roots ( and ); for only one. A cubic always has at most three real roots, but it may have fewer. The other roots have not vanished: they have become complex.
Three real roots, or one?
Move the sliders and trace along the curves to read off values.
- y = x³ + cx
- y = x³ + cx: y = −2
Every cubic graph you can draw crosses the axis at least once. That is true for every polynomial of odd degree. The proof needs the intermediate value theorem about continuous functions (see introductory calculus).
Exercises
1. Polynomials
Warm-upHumanWhat is the degree of ?
2. Polynomials
Warm-upHumanFind the remainder when is divided by .
3. Polynomials
CoreHumanFor which number is a factor of ?
4. Polynomials
CoreHumanFind all real roots of . Enter them as a set, for example {1, 2, 3}.
5. Polynomials
CoreHumanFor , which expression equals ?
6. Polynomials
CoreHumanA polynomial with real coefficients has degree . How many different real roots could it have? Choose all that are possible.
7. Polynomials
StretchHumanIn the proof of the root bound we wrote: and , so . Modulo this step fails and has four roots. Which property of the real numbers does the step use?
8. Polynomials
CoreFormalWhich Lean statement formalises the factor theorem for a polynomial p : R[X] and a number a : R? (Recall: C a is the constant polynomial and p.eval a is .)
9. Polynomials
StretchComputationalWrite divide_by_linear(coeffs, a) that divides by using synthetic division. coeffs lists the coefficients of from the highest power down (so is [2, -3, -11, 6]). Return a pair (quotient, remainder), where quotient is the list of the quotient's coefficients.
Common misconceptions
Misconception
Cancelling terms across a fraction. is not . You may cancel common factors of the whole numerator and the whole denominator, never single terms: (for ). Try : .
Misconception
"Every polynomial factorises over the integers." Most do not. needs , needs , and has no rational root at all (rational root test). Factorising with integer coefficients is a special event, which is why the rational root test is so useful for spotting it.
Misconception
"A polynomial of degree has exactly real roots." It has at most . has none, has one, and has a single root counted twice. Over the complex numbers, counting repeated roots with their multiplicity, there are exactly — but that is the fundamental theorem of algebra, not the root bound.
Misconception
"The remainder on dividing by is ." Write : the remainder is .
Misconception
"." The square of a sum has a middle term: . With : .
Many ways of seeing
Number theory— Polynomials behave like integers
The integers and the polynomials over a field share a division algorithm: integers with remainders smaller in size, polynomials with remainders smaller in degree. Euclid's algorithm therefore works for polynomials too, computing greatest common divisors. Irreducible polynomials play the role of primes, and factorisation is unique up to constant factors. Both are examples of a Euclidean domain, an idea you will meet with rings. Number theorists also turn the analogy around: polynomials over the finite field with elements are a laboratory where many hard questions about integers become provable.
Algebra— A polynomial is not just a function
Over the integers modulo , the polynomial is not the zero polynomial. Yet it gives at both and (because there), so it is the zero function. Algebraists therefore treat a polynomial as its list of coefficients, a formal object. Over the distinction disappears: by the identity theorem, two different real polynomials differ at all but finitely many points. Evaluation at respects both operations, and . In modern language it is a ring homomorphism, and the remainder theorem says that and the constant leave the same remainder on division by .
Geometry— Roots you can see
The real roots of are where the graph meets the -axis, and a repeated root is where the graph touches the axis without crossing. One equation in two variables, such as or , describes a curve. Studying the shapes cut out by polynomial equations, and the algebra that controls them, is algebraic geometry (see algebraic geometry). There, the root bound grows into Bézout's theorem: two plane curves of degrees and with no common component meet in at most points.
Computation— Horner's rule is the fast way to evaluate
Computing term by term takes about multiplications if each power is computed afresh. Synthetic division computes as , which takes only multiplications and additions. This "Horner scheme" is how computers evaluate polynomials. Root-finding methods such as Newton's method approximate roots that have no exact formula (see numerical methods).
Wonder Trails
The quadratic with four roots lives in clock arithmetic. This optional trail explores that world:
Wonder Trail · Optional · never gradedClock arithmeticIt's 9 o'clock. What time will it be in 5 hours — and in 29 hours? Can a clock teach us a whole new kind of arithmetic?Follow the trailHistory and global context
- Mesopotamia. Old Babylonian scribes (around 1800–1600 BCE) solved problems that we would write as quadratic equations. They also compiled tables of values of that could be used for certain cubic problems.
- The Islamic world. In the 9th century, al-Khwārizmī's book on al-jabr (from which "algebra" takes its name) treated quadratic equations systematically. Around 1070, ʿUmar al-Khayyām (Omar Khayyam) classified cubic equations and solved them geometrically by intersecting conic sections. In the 12th century Sharaf al-Dīn al-Ṭūsī studied when cubics have positive roots and how to approximate them numerically.
- China. Qin Jiushao's Mathematical Treatise in Nine Sections (1247) solved polynomial equations of high degree numerically, by a procedure essentially the same as the method published in Europe by Ruffini and Horner in the early 19th century. Zhu Shijie's Jade Mirror of the Four Unknowns (1303) handled systems of polynomial equations in up to four unknowns.
- Renaissance Italy. Scipione del Ferro and Niccolò Tartaglia found formulas for cubic equations, and Lodovico Ferrari for quartics; Gerolamo Cardano published them in Ars Magna (1545).
- The factor theorem and beyond. René Descartes's La Géométrie (1637) stated that a polynomial with root is divisible by . Paolo Ruffini (1799) and Niels Henrik Abel (1824) showed that there is no general formula using radicals for equations of degree five, and Évariste Galois explained exactly which equations can be solved that way (see Galois theory). Carl Friedrich Gauss's dissertation (1799) gave a proof of the fundamental theorem of algebra. By modern standards it had a gap, later filled. Jean-Robert Argand gave a different proof in 1806.
Further reading
- I. M. Gelfand and A. Shen, Algebra (1993) — polynomials, division and factorisation, written for strong school students.
- E. J. Barbeau, Polynomials (1989) — a problem book that goes from school algebra to research-flavoured questions.
- V. V. Prasolov, Polynomials (2004) — a wide-ranging survey for the ambitious reader.
- Richard Courant and Herbert Robbins, What Is Mathematics? (1941) — includes a proof of the fundamental theorem of algebra.