Skip to content
The Lumenary
Grades 9–12Ages 14–18 75 min

Polynomials

Expressions built from one letter by adding and multiplying — and the theorem that ties their roots to their factors.

Formally verified · 14 LeanComputationally tested · 2 PythonAI-drafted · awaiting human reviewMathematically reviewed: Awaiting human review

Your guides: Chloe, Margaret, Gideon

MotivationH

A box from a sheet of card

A cooperative of packaging makers in Oaxaca folds open boxes from rectangular sheets of card, 3030 cm by 2020 cm. From each corner they cut a square of side xx cm and fold up the sides. The box is xx cm tall, with a base of (30−2x)(30 - 2x) by (20−2x)(20 - 2x) cm, so its volume is

V(x)=x(30−2x)(20−2x)=4x3−100x2+600xcubic centimetres.V(x) = x(30 - 2x)(20 - 2x) = 4x^3 - 100x^2 + 600x \quad \text{cubic centimetres}.

A customer wants boxes holding exactly one litre, 1000 cm31000\ \text{cm}^3. Trying x=5x = 5 gives V(5)=5⋅20⋅10=1000V(5) = 5 \cdot 20 \cdot 10 = 1000. Success! But is x=5x = 5 the only size that works? A shorter, wider box might use the card differently.

We need to solve 4x3−100x2+600x−1000=04x^3 - 100x^2 + 600x - 1000 = 0, 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.)

IntuitionH

Polynomials are like numbers in base x

The number 312312 means 3⋅102+1⋅10+23 \cdot 10^2 + 1 \cdot 10 + 2. The expression 3x2+x+23x^2 + x + 2 is the same pattern with the base 1010 replaced by a letter, and putting x=10x = 10 gives back 312312.

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).

DefinitionsH

Definitions

Definition— polynomial

A polynomial in xx with real coefficients is an expression

p(x)=anxn+an−1xn−1+⋯+a1x+a0,p(x) = a_n x^n + a_{n-1} x^{n-1} + \cdots + a_1 x + a_0,

where n≥0n \ge 0 is a whole number and a0,…,ana_0, \dots, a_n are real numbers, the coefficients. Two polynomials are equal when their coefficients of each power of xx agree.

Definition— degree, leading coefficient

If an≠0a_n \neq 0, then nn is the degree of pp, written deg⁡p\deg p, and ana_n is its leading coefficient. A polynomial whose leading coefficient is 11 is called monic. The zero polynomial (all coefficients 00) has no degree: by convention we leave deg⁡0\deg 0 undefined (some books write −∞-\infty).

Definition— root

A number aa is a root (or zero) of pp if p(a)=0p(a) = 0. Here p(a)p(a) means: substitute aa for xx and calculate.

Degree-00 polynomials are the non-zero constants; degrees 1,2,3,41, 2, 3, 4 are called linear, quadratic, cubic and quartic. Expressions such as 1/x1/x, x\sqrt{x} or 2x2^x are not polynomials: only whole-number powers of xx are allowed.

Theorem— Lemma (degree of a product)

If pp and qq are non-zero polynomials with real coefficients, then pq≠0pq \ne 0 and deg⁡(pq)=deg⁡p+deg⁡q\deg(pq) = \deg p + \deg q. Also deg⁡(p+q)≤max⁡(deg⁡p,deg⁡q)\deg(p + q) \le \max(\deg p, \deg q) when p+q≠0p + q \neq 0.

Proof

Let the leading terms be axma x^m and bxnb x^n with a,b≠0a, b \ne 0. When we multiply out pqpq, the only way to make xm+nx^{m+n} is axm⋅bxna x^m \cdot b x^n; every other product of terms has a smaller power. So the coefficient of xm+nx^{m+n} in pqpq is abab, 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 max⁡(m,n)\max(m, n) occurs in either polynomial.

∎

The sum can have a smaller degree than both summands: (x2+x)+(−x2+1)=x+1(x^2 + x) + (-x^2 + 1) = x + 1.

Worked examplesH

Worked examples

Example— Special products

These identities hold for all numbers a,ba, b (expand the right-hand sides to check):

(a+b)2=a2+2ab+b2,a2−b2=(a−b)(a+b),(a + b)^2 = a^2 + 2ab + b^2, \qquad a^2 - b^2 = (a - b)(a + b),a3+b3=(a+b)(a2−ab+b2),a3−b3=(a−b)(a2+ab+b2).a^3 + b^3 = (a + b)(a^2 - ab + b^2), \qquad a^3 - b^3 = (a - b)(a^2 + ab + b^2).

Read from right to left they multiply; read from left to right they factorise. For example x4−16=(x2−4)(x2+4)=(x−2)(x+2)(x2+4)x^4 - 16 = (x^2 - 4)(x^2 + 4) = (x - 2)(x + 2)(x^2 + 4), and 8x3+27=(2x)3+33=(2x+3)(4x2−6x+9)8x^3 + 27 = (2x)^3 + 3^3 = (2x + 3)(4x^2 - 6x + 9).

Example— Factorising by grouping

x3+2x2−9x−18=x2(x+2)−9(x+2)=(x+2)(x2−9)=(x+2)(x−3)(x+3).x^3 + 2x^2 - 9x - 18 = x^2(x + 2) - 9(x + 2) = (x + 2)(x^2 - 9) = (x + 2)(x - 3)(x + 3).

So the roots are −2,3,−3-2, 3, -3: a product is zero exactly when one of its factors is.

Example— Non-examples: what does not factorise

  • x2+1x^2 + 1 has no real roots (x2+1≥1x^2 + 1 \ge 1 for every real xx), so it has no factor x−ax - a with aa real. It does factorise over the complex numbers: x2+1=(x−i)(x+i)x^2 + 1 = (x - i)(x + i).
  • x2−2=(x−2)(x+2)x^2 - 2 = (x - \sqrt 2)(x + \sqrt 2) factorises with real coefficients but not with rational ones, because 2\sqrt 2 is irrational (see real numbers).

Whether a polynomial factorises depends on which numbers you allow as coefficients.

Example— Long division

Divide p(x)=x4+3x3−x+5p(x) = x^4 + 3x^3 - x + 5 by d(x)=x2+1d(x) = x^2 + 1. At each step, divide the leading term of what is left by the leading term x2x^2 of dd:

  1. x4÷x2=x2x^4 \div x^2 = x^2. Subtract x2(x2+1)=x4+x2x^2(x^2 + 1) = x^4 + x^2: left with 3x3−x2−x+53x^3 - x^2 - x + 5.
  2. 3x3÷x2=3x3x^3 \div x^2 = 3x. Subtract 3x(x2+1)=3x3+3x3x(x^2 + 1) = 3x^3 + 3x: left with −x2−4x+5-x^2 - 4x + 5.
  3. −x2÷x2=−1-x^2 \div x^2 = -1. Subtract −1⋅(x2+1)-1 \cdot (x^2 + 1): left with −4x+6-4x + 6.

The leftover −4x+6-4x + 6 has degree 1<2=deg⁡d1 < 2 = \deg d, so we stop:

x4+3x3−x+5=(x2+3x−1)(x2+1)+(−4x+6).x^4 + 3x^3 - x + 5 = (x^2 + 3x - 1)(x^2 + 1) + (-4x + 6).

The quotient is x2+3x−1x^2 + 3x - 1 and the remainder is −4x+6-4x + 6.

Example— Synthetic division by x − a

Dividing by x−ax - a is so common that it has a shortcut, synthetic division (Horner's or Ruffini's rule). Divide 2x3−3x2−11x+62x^3 - 3x^2 - 11x + 6 by x−3x - 3: write the coefficients, bring down the first, then repeatedly multiply by 33 and add:

22−3-3−11-1166
×3\times 36699−6-6
sum2233−2-20\mathbf{0}

The bottom row gives the quotient 2x2+3x−22x^2 + 3x - 2 and the remainder 00. So 2x3−3x2−11x+6=(x−3)(2x2+3x−2)=(x−3)(2x−1)(x+2)2x^3 - 3x^2 - 11x + 6 = (x - 3)(2x^2 + 3x - 2) = (x - 3)(2x - 1)(x + 2).

Example— Finishing the box

Back to the box: V(x)−1000=4(x3−25x2+150x−250)V(x) - 1000 = 4(x^3 - 25x^2 + 150x - 250), and we know x=5x = 5 is a root. Synthetic division by x−5x - 5 gives

x3−25x2+150x−250=(x−5)(x2−20x+50).x^3 - 25x^2 + 150x - 250 = (x - 5)(x^2 - 20x + 50).

The quadratic factor has roots x=10±50=10±52x = 10 \pm \sqrt{50} = 10 \pm 5\sqrt 2, about 2.932.93 and 17.0717.07. A cut of 17.0717.07 cm is impossible on a 2020 cm side (we need 0<x<100 < x < 10), but x=10−52≈2.93x = 10 - 5\sqrt 2 \approx 2.93 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.

ProofH

Division, remainders and roots

Theorem— Division algorithm

Let pp and dd be polynomials with real (or rational) coefficients, d≠0d \ne 0. Then there are unique polynomials qq (the quotient) and rr (the remainder) with

p=q d+randr=0 or deg⁡r<deg⁡d.p = q\,d + r \qquad \text{and} \qquad r = 0 \text{ or } \deg r < \deg d.

Proof

Existence, by strong induction on the degree of pp. If p=0p = 0 or deg⁡p<deg⁡d\deg p < \deg d, take q=0q = 0 and r=pr = p. Otherwise let pp have leading term axna x^n and dd have leading term bxmb x^m, with n≥mn \ge m. The polynomial

p1=p−abxn−mdp_1 = p - \tfrac{a}{b} x^{n-m} d

has the xnx^n terms cancelled, so p1=0p_1 = 0 or deg⁡p1<n\deg p_1 < n. By the induction hypothesis p1=q1d+rp_1 = q_1 d + r with r=0r = 0 or deg⁡r<deg⁡d\deg r < \deg d. Then p=(q1+abxn−m)d+rp = \big(q_1 + \tfrac{a}{b} x^{n-m}\big) d + r. (This is exactly one step of long division.)

Uniqueness. Suppose q1d+r1=q2d+r2q_1 d + r_1 = q_2 d + r_2, both remainders being 00 or of degree less than deg⁡d\deg d. Then (q1−q2) d=r2−r1(q_1 - q_2)\,d = r_2 - r_1. If q1≠q2q_1 \ne q_2, the lemma on products says the left side has degree deg⁡(q1−q2)+deg⁡d≥deg⁡d\deg(q_1 - q_2) + \deg d \ge \deg d. But the right side is 00 or has degree less than deg⁡d\deg d. That is impossible, so q1=q2q_1 = q_2, and then r1=r2r_1 = r_2.

∎

We needed to divide by the leading coefficient bb. That is why the theorem is stated for rational or real coefficients. With integer coefficients it still works when dd is monic, such as d=x−ad = x - a.

Theorem— Remainder theorem

The remainder when p(x)p(x) is divided by x−ax - a is the number p(a)p(a). That is, p(x)=(x−a) q(x)+p(a)p(x) = (x - a)\,q(x) + p(a) for some polynomial qq.

Proof

First proof. By the division algorithm, p(x)=(x−a)q(x)+rp(x) = (x - a)q(x) + r where rr is 00 or has degree less than 11, so rr is a constant. Substituting x=ax = a gives p(a)=0⋅q(a)+r=rp(a) = 0 \cdot q(a) + r = r.

Second proof, without the division algorithm. For each k≥1k \ge 1,

xk−ak=(x−a)(xk−1+xk−2a+⋯+xak−2+ak−1),x^k - a^k = (x - a)\left(x^{k-1} + x^{k-2}a + \cdots + x a^{k-2} + a^{k-1}\right),

as you can check by expanding (the middle terms cancel in pairs). If p(x)=∑kckxkp(x) = \sum_k c_k x^k then

p(x)−p(a)=∑kck(xk−ak),p(x) - p(a) = \sum_{k} c_k \left(x^k - a^k\right),

and x−ax - a divides every term, so it divides p(x)−p(a)p(x) - p(a).

∎

Theorem— Factor theorem

x−ax - a is a factor of p(x)p(x) if and only if p(a)=0p(a) = 0.

Proof

If p(x)=(x−a)q(x)p(x) = (x - a)q(x), then p(a)=(a−a) q(a)=0p(a) = (a - a)\,q(a) = 0. Conversely, if p(a)=0p(a) = 0, the remainder theorem gives p(x)=(x−a)q(x)+0p(x) = (x - a)q(x) + 0.

∎

Theorem— Root bound

A non-zero polynomial of degree nn with real (or complex) coefficients has at most nn roots.

Proof

Induction on nn. A polynomial of degree 00 is a non-zero constant and has no roots. Now let deg⁡p=n≥1\deg p = n \ge 1 and assume the statement for degree n−1n - 1. If pp has no roots, we are done. Otherwise pick a root aa. By the factor theorem p(x)=(x−a)q(x)p(x) = (x - a)q(x), and by the lemma deg⁡q=n−1\deg q = n - 1.

Let bb be any root of pp other than aa. Then 0=p(b)=(b−a) q(b)0 = p(b) = (b - a)\,q(b). Since b−a≠0b - a \ne 0 and a product of real (or complex) numbers is zero only if a factor is zero, q(b)=0q(b) = 0. So every root of pp is either aa or a root of qq. By the induction hypothesis qq has at most n−1n - 1 roots, so pp has at most 1+(n−1)=n1 + (n - 1) = n.

∎

Theorem— Corollary (identity theorem)

If two polynomials pp and qq, each zero or of degree at most nn, take the same values at n+1n + 1 different numbers, then p=qp = q.

Proof

If p≠qp \ne q, then p−qp - q is a non-zero polynomial of degree at most nn with at least n+1n + 1 roots, contradicting the root bound.

∎

So a polynomial identity of degree nn can be proved by checking n+1n + 1 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 p(x)=anxn+⋯+a1x+a0p(x) = a_n x^n + \cdots + a_1 x + a_0 have integer coefficients, with an≠0a_n \ne 0 and a0≠0a_0 \neq 0. If a fraction r/sr/s in lowest terms is a root of pp, then rr divides a0a_0 and ss divides ana_n.

Proof

Substitute x=r/sx = r/s and multiply by sns^n:

anrn+an−1rn−1s+⋯+a1rsn−1+a0sn=0.a_n r^n + a_{n-1} r^{n-1} s + \cdots + a_1 r s^{n-1} + a_0 s^n = 0.

Every term except the last contains the factor rr, so rr divides a0sna_0 s^n. Since rr and ss have no common prime factor, rr shares none with sns^n, and so rr divides a0a_0 (by unique factorisation; see divisibility). Similarly every term except the first contains ss, so ss divides anrna_n r^n and hence ss divides ana_n.

∎

For 2x3−3x2−11x+62x^3 - 3x^2 - 11x + 6 the only candidates are ±1,±2,±3,±6,±12,±32\pm 1, \pm 2, \pm 3, \pm 6, \pm \tfrac12, \pm \tfrac32. Testing them finds −2,12,3-2, \tfrac12, 3. For x3−2x^3 - 2 the candidates ±1,±2\pm 1, \pm 2 all fail, which proves that 23\sqrt[3]{2} 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 nn splits into nn linear factors over C\mathbb{C}. So it has exactly nn 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.

Formal mathematicsF

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 aa, p.eval a is p(a)p(a) 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:

diff_of_squaresLean 4Proved here from basic factsFormally verified
/-- **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
Axioms used: propext, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor
sum_and_diff_of_cubesLean 4Proved here from basic factsFormally verified
/-- **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 <;> ring
Axioms used: propext, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor

The second proof of the remainder theorem has two steps. First, x−ax - a divides xn−anx^n - a^n, proved by induction from xn+1−an+1=x(xn−an)+an(x−a)x^{n+1} - a^{n+1} = x(x^n - a^n) + a^n(x - a):

sub_dvd_pow_sub_pow'Lean 4Proved here from basic factsFormally verified
/-- **`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 ring
Axioms used: propext, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor

Then p−p(a)p - p(a) is built from single terms c xkc\,x^k by adding, and each term is handled by the lemma:

remainder_theoremLean 4Proved here from basic factsFormally verified
/-- **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)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor

Mathlib states the same theorem as "the remainder on dividing by the monic polynomial X−aX - a is the constant p(a)p(a)". Our version above is proved here, from more basic facts; this one only applies a library theorem:

remainder_theorem_libraryLean 4Applies a library theoremFormally verified
/-- **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
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor
factor_theoremLean 4Proved here from basic factsFormally verified
/-- **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 this
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor

For the division algorithm we take existence from Mathlib (over any field, such as Q\mathbb{Q} or R\mathbb{R}) and prove uniqueness with the degree argument of the lesson:

division_existsLean 4Applies a library theoremFormally verified
/-- **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⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor
division_uniqueLean 4Proved here from basic factsFormally verified
/-- **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⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor

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 s3s^3, just as in the proof:

rational_root_cubicLean 4Proved here from basic factsFormally verified
/-- **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 h2
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor

The root bound is proved over any integral domain, a number system with the zero-product property, which covers Z\mathbb{Z}, Q\mathbb{Q}, R\mathbb{R} and C\mathbb{C} at once. The proof is the lesson's induction, organised by adding one root at a time:

card_roots_le_natDegreeLean 4Proved here from basic factsFormally verified
/-- **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)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor
card_roots_libraryLean 4Applies a library theoremFormally verified
/-- **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
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor
eq_of_agreeLean 4Proved here from basic factsFormally verified
/-- **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)
  omega
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor

Finally, the zero-product property really is needed. In ZMod 8, the integers modulo 8, the root bound fails, while modulo the prime 77 it holds:

four_roots_mod_eightLean 4Proved here from basic factsFormally verified
/-- **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
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor
two_roots_mod_sevenLean 4Proved here from basic factsFormally verified
/-- **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
  decide
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/Polynomials.leanTry it in the Lean web editor
ComputationC

Dividing exactly, and counting roots in clock arithmetic

Synthetic division and the remainder theoremPythonExact computationExperimental evidenceComputationally tested
"""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()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

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 x3−2x^3 - 2 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 23\sqrt[3]{2} is irrational.

Next, the root bound in clock arithmetic. Where does it fail, and where does an exhaustive search find no failure at all?

More roots than the degree? Polynomials modulo nPythonExhaustive finite checkCounterexampleComputationally tested
"""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()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

Modulo a composite number such as 88, 1515 or 2424, 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 33, exactly as the proof predicts.

Explore

Explore: roots and factors

Move the sliders rr, ss and tt. The cubic y=a(x−r)(x−s)(x−t)y = a(x - r)(x - s)(x - t) crosses the xx-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 aa negative do?

A cubic with chosen roots

Move the sliders and trace along the curves to read off values.

rst
  • y = a(x − r)(x − s)(x − t)
  • y = a(x − r)(x − s)(x − t): y = −1.5

Now change cc in y=x3+cxy = x^3 + cx. For c<0c < 0 there are three real roots (00 and ±−c\pm\sqrt{-c}); for c≥0c \ge 0 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

Exercises

1. Polynomials

Warm-upHuman

What is the degree of (x3+2x)(4x5−x+1)(x^3 + 2x)(4x^5 - x + 1)?

2. Polynomials

Warm-upHuman

Find the remainder when p(x)=x3−4x2+2x+7p(x) = x^3 - 4x^2 + 2x + 7 is divided by x−3x - 3.

3. Polynomials

CoreHuman

For which number kk is x−2x - 2 a factor of x3+kx−6x^3 + kx - 6?

4. Polynomials

CoreHuman

Find all real roots of x3−2x2−5x+6x^3 - 2x^2 - 5x + 6. Enter them as a set, for example {1, 2, 3}.

Write elements separated by commas. Order and repeats don’t matter — just like in a set!

5. Polynomials

CoreHuman

For x≠0x \ne 0, which expression equals x2+1x\dfrac{x^2 + 1}{x}?

Choose one

6. Polynomials

CoreHuman

A polynomial with real coefficients has degree 44. How many different real roots could it have? Choose all that are possible.

Choose all that apply

7. Polynomials

StretchHuman

In the proof of the root bound we wrote: 0=p(b)=(b−a) q(b)0 = p(b) = (b - a)\,q(b) and b−a≠0b - a \ne 0, so q(b)=0q(b) = 0. Modulo 88 this step fails and x2−1x^2 - 1 has four roots. Which property of the real numbers does the step use?

Choose one

8. Polynomials

CoreFormal

Which Lean statement formalises the factor theorem for a polynomial p : R[X] and a number a : R? (Recall: C a is the constant polynomial aa and p.eval a is p(a)p(a).)

Choose one

9. Polynomials

StretchComputational

Write divide_by_linear(coeffs, a) that divides p(x)p(x) by x−ax - a using synthetic division. coeffs lists the coefficients of pp from the highest power down (so 2x3−3x2−11x+62x^3 - 3x^2 - 11x + 6 is [2, -3, -11, 6]). Return a pair (quotient, remainder), where quotient is the list of the quotient's coefficients.

Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.
Common misconceptionsH

Common misconceptions

Misconception

Cancelling terms across a fraction. x2+1x\dfrac{x^2 + 1}{x} is not x+1x + 1. You may cancel common factors of the whole numerator and the whole denominator, never single terms: x2+1x=x+1x\dfrac{x^2 + 1}{x} = x + \dfrac{1}{x} (for x≠0x \ne 0). Try x=2x = 2: 52≠3\tfrac{5}{2} \ne 3.

Misconception

"Every polynomial factorises over the integers." Most do not. x2−2x^2 - 2 needs 2\sqrt 2, x2+1x^2 + 1 needs ii, and x3−2x^3 - 2 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 nn has exactly nn real roots." It has at most nn. x2+1x^2 + 1 has none, x3+xx^3 + x has one, and (x−1)2(x - 1)^2 has a single root counted twice. Over the complex numbers, counting repeated roots with their multiplicity, there are exactly nn — but that is the fundamental theorem of algebra, not the root bound.

Misconception

"The remainder on dividing by x+2x + 2 is p(2)p(2)." Write x+2=x−(−2)x + 2 = x - (-2): the remainder is p(−2)p(-2).

Misconception

"(a+b)2=a2+b2(a + b)^2 = a^2 + b^2." The square of a sum has a middle term: (a+b)2=a2+2ab+b2(a + b)^2 = a^2 + 2ab + b^2. With a=b=1a = b = 1: 4≠24 \ne 2.

ViewpointsH

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 pp elements are a laboratory where many hard questions about integers become provable.

Algebra— A polynomial is not just a function

Over the integers modulo 22, the polynomial x2+xx^2 + x is not the zero polynomial. Yet it gives 00 at both x=0x = 0 and x=1x = 1 (because 1+1=01 + 1 = 0 there), so it is the zero function. Algebraists therefore treat a polynomial as its list of coefficients, a formal object. Over R\mathbb{R} the distinction disappears: by the identity theorem, two different real polynomials differ at all but finitely many points. Evaluation at aa respects both operations, (p+q)(a)=p(a)+q(a)(p + q)(a) = p(a) + q(a) and (pq)(a)=p(a)q(a)(pq)(a) = p(a)q(a). In modern language it is a ring homomorphism, and the remainder theorem says that pp and the constant p(a)p(a) leave the same remainder on division by x−ax - a.

Geometry— Roots you can see

The real roots of pp are where the graph y=p(x)y = p(x) meets the xx-axis, and a repeated root is where the graph touches the axis without crossing. One equation in two variables, such as y2=x3−xy^2 = x^3 - x or x2+y2=1x^2 + y^2 = 1, 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 mm and nn with no common component meet in at most mnmn points.

Computation— Horner's rule is the fast way to evaluate

Computing anxn+⋯+a0a_n x^n + \cdots + a_0 term by term takes about n2/2n^2/2 multiplications if each power is computed afresh. Synthetic division computes p(a)p(a) as (⋯((ana+an−1)a+an−2)a+⋯ )a+a0(\cdots((a_n a + a_{n-1})a + a_{n-2})a + \cdots)a + a_0, which takes only nn multiplications and nn 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

Wonder Trails

History & global context

History 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 n3+n2n^3 + n^2 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 aa is divisible by x−ax - a. 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

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.