Introduction

Dividing polynomials the "long division" way works, but it is slow: you rewrite the whole dividend at every step, keep track of every power of xx, and it is easy to drop a sign. In 1804 the Italian mathematician Paolo Ruffini described a shortcut for the one case that shows up constantly — dividing by a simple linear factor (x−r)(x - r) — and it survives in classrooms today as synthetic division.

The trick is that once you fix the divisor to be (x−r)(x - r), you don't need xx at all. Every step of the division can be done with just the coefficients of the polynomial, arranged in a small table, using only multiplication and addition. Three coefficients in, three numbers out, one arithmetic operation repeated down a row.

Even better, the very last number the table produces is not scrap — it is p(r)p(r), the value of the polynomial at rr, obtained as a side effect of the division. That "free" bonus is not a coincidence; it is the Remainder Theorem wearing a disguise.

Try It

Pick a polynomial and a root rr, then step through the table. Each column repeats the same two moves: multiply the last row entry by rr and add it under the next coefficient, then add that column down.

<p class="hint">The polynomial is <b>p(x) = x&sup3; &minus; 6x&sup2; + 11x &minus; 6</b> (roots 1, 2 and 3). Pick a root r, then press Step to bring down, multiply and add across the row — one column at a time.</p>
<div class="controls">
  <label for="root-select">Divide by (x - r):</label>
  <select id="root-select">
    <option value="1">r = 1</option>
    <option value="2">r = 2</option>
    <option value="3">r = 3</option>
    <option value="4">r = 4</option>
    <option value="-1">r = -1</option>
  </select>
  <button id="step" type="button">Step</button>
  <button id="auto" type="button">Auto-run</button>
  <button id="reset" type="button" class="ghost">Reset</button>
</div>
<div id="table" class="table"></div>
<div class="status" id="status">Bring down the first coefficient, then press Step.</div>
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; color: #222; margin: 0; }
.hint { font-size: .9rem; color: #444; margin: 0 0 .7rem; line-height: 1.45; }
.controls { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-bottom: .8rem; }
.controls label { font-size: .85rem; font-weight: 600; color: #1d3557; }
select { font: 600 14px system-ui, sans-serif; padding: .35rem .5rem; border-radius: 6px; border: 1px solid #adb1b8; }
.table { display: grid; grid-template-columns: repeat(5, 62px); gap: 4px; margin: .5rem 0; font: 700 16px ui-monospace, monospace; }
.cell { height: 42px; display: flex; align-items: center; justify-content: center; border-radius: 6px; }
.cell.coeff { background: #e8eef3; color: #1d3557; border: 1px solid #cdd9e3; }
.cell.mult { background: #fff3cd; color: #8a6d1d; border: 1px dashed #e0b93d; }
.cell.sum { background: #c9ccd1; color: #222; border: 1px solid #adb1b8; }
.cell.sum.active { background: #1d3557; color: #fff; }
.cell.sum.remainder { background: #0a7d33; color: #fff; }
.cell.empty { visibility: hidden; }
.status { font-size: 1rem; font-weight: 600; margin: .5rem 0; min-height: 1.4em; }
.status.ok { color: #0a7d33; }
.status.info { color: #1d3557; }
.btns { display: flex; gap: .5rem; }
button { font: 600 14px system-ui, sans-serif; padding: .45rem .9rem; border: 1px solid #1d3557;
         background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; }
button.ghost { background: #fff; color: #1d3557; }
button:disabled { opacity: .5; cursor: default; }
const i18nFmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Fixed polynomial: coefficients of x^3 - 6x^2 + 11x - 6, highest degree first.
const COEFFS = [1, -6, 11, -6]; // coefficients 1, -6, 11, -6
let r = 1;
let col = 0; // next column to fill
let running = null;
const row = [];

function polyLabel(){
  // builds the human-readable polynomial label for the console
  return 'p(x) = x' + '³' + ' − 6x' + '²' + ' + 11x − 6';
}

function reset(){
  row.length = 0;
  row.push(COEFFS[0]);
  col = 1;
  clearInterval(running); running = null;
  render();
  setStatus('Bring down the first coefficient, then press Step.', 'info');
}

function step(){
  if (col >= COEFFS.length) return false;
  const brought = COEFFS[col] + row[col-1]*r; // multiply the last row value by r, add the next coefficient
  row.push(brought);
  col++;
  render();
  if (col === COEFFS.length){
    setStatus(i18nFmt('Done! The remainder is %pr% — and that equals p(%r%), computed for free.', { r: r, pr: row[row.length-1] }), 'ok');
    return false;
  }
  setStatus(i18nFmt('Multiplied by r and added into column %col%.', { col: col }), 'info');
  return true;
}

function render(){
  const t = document.getElementById('table'); t.innerHTML = '';
  const n = COEFFS.length;
  // top row = coefficients, middle row = multiply-by-r products, bottom row = running sums
  for (let i = 0; i < n; i++){
    const d = document.createElement('div');
    d.className = 'cell coeff';
    d.textContent = COEFFS[i];
    t.appendChild(d);
  }
  const rLabel = document.createElement('div');
  rLabel.className = 'cell empty';
  t.appendChild(rLabel);
  for (let i = 0; i < n; i++){
    const d = document.createElement('div');
    if (i === 0 || i >= row.length){ d.className = 'cell empty'; }
    else { d.className = 'cell mult'; d.textContent = '+' + (row[i-1]*r); }
    t.appendChild(d);
  }
  const mLabel = document.createElement('div');
  mLabel.className = 'cell empty';
  t.appendChild(mLabel);
  for (let i = 0; i < n; i++){
    const d = document.createElement('div');
    if (i >= row.length){ d.className = 'cell empty'; }
    else {
      const isLast = (i === n-1) && (row.length === n);
      d.className = 'cell sum' + (isLast ? ' remainder' : (i === row.length-1 ? ' active' : ''));
      d.textContent = row[i];
    }
    t.appendChild(d);
  }
}

function setStatus(t, cls){ const s = document.getElementById('status'); s.textContent = t; s.className = 'status ' + cls; }

document.getElementById('root-select').addEventListener('change', (e) => {
  r = Number(e.target.value);
  reset();
});
document.getElementById('step').addEventListener('click', step);
document.getElementById('auto').addEventListener('click', () => {
  if (running) return;
  running = setInterval(() => { if (!step()) { clearInterval(running); running = null; } }, 650);
});
document.getElementById('reset').addEventListener('click', reset);

console.log(polyLabel(), '(open the console to see the label)'); // log the polynomial once at start
reset();
Result
Console

Watch what happens to the very last cell. It's the remainder of the division — and it always matches p(r)p(r) computed the ordinary way, plugging rr straight into the polynomial. Try a root where the remainder lands on 00: that means (x−r)(x - r) divides the polynomial exactly, and rr is one of its roots.

The Real Complexity

Synthetic division looks like a party trick, but it is doing exactly the right amount of work — no more, no less.

  • Why it works. Write p(x)=(x−r)⋅q(x)+cp(x) = (x - r) \cdot q(x) + c for some quotient q(x)q(x) and constant cc. Matching coefficients on both sides shows that each coefficient of qq is the previous one times rr plus the next coefficient of pp — precisely the "multiply, then add" step of the table. That is the whole proof; there is no hidden machinery.
  • The remainder is p(r)p(r). Plug x=rx = r into p(x)=(x−r)⋅q(x)+cp(x) = (x - r)\cdot q(x) + c: the first term vanishes, leaving p(r)=cp(r) = c. This is the Remainder Theorem, and it is why the last cell of the table is never wasted.
  • The Factor Theorem falls out for free. If the remainder is 00, then p(r)=0p(r) = 0, so rr is a root and (x−r)(x - r) is an exact factor — the table doubles as a root test.
  • Cost. For a degree-nn polynomial the table performs exactly nn multiplications and nn additions — O(n)O(n) arithmetic operations. This is not a lucky shortcut; it is Horner's method for evaluating a polynomial, just laid out row-by-row. Naive evaluation by computing each power xkx^k separately costs O(n2)O(n^2) multiplications, and even computing the powers efficiently still needs more bookkeeping than this single running total.

So synthetic division is the linear-time algorithm for a task — dividing by (x−r)(x-r) and evaluating at rr — where a naive approach would cost quadratic work, and it is a special case of the general polynomial long division. It is a small, complete example of finding the operation count a problem actually needs.

Where It Matters

The row of "multiply then add" is small, but it shows up everywhere polynomials do:

  • Fast evaluation. Horner's method — the same recurrence as synthetic division — is the standard way calculators and compilers evaluate polynomials, cutting the multiplication count from O(n2)O(n^2) to O(n)O(n).
  • Finding roots by hand. Once you find one integer root by testing candidates (say, via the rational root theorem), synthetic division deflates the polynomial to a lower-degree quotient, so you can hunt for the remaining roots in a smaller problem.
  • Numerical stability. Horner-style evaluation is also the numerically preferred way to compute p(r)p(r) in floating point, since it avoids separately forming large powers of xx that can overflow or lose precision.
  • Teaching structure. It is a rare case in algebra where a mechanical shortcut is provably the same algorithm as the theoretically optimal one — a nice bridge between a classroom trick and algorithm complexity.

Learn synthetic division and you've already learned Horner's method — the quiet workhorse behind polynomial evaluation in everything from graphing calculators to computer algebra systems.

Conclusion

Ruffini's rule looks like a bookkeeping shortcut, but it is a complete algorithm hiding in plain sight: it divides by (x−r)(x - r) in O(n)O(n) steps, and its very last output is p(r)p(r), free of charge, courtesy of the Remainder Theorem.

The next time a table of "bring down, multiply, add" saves you a page of long division, remember that you are running Horner's method — the same O(n)O(n) idea that shows up whenever a computer, not just a student, needs to evaluate a polynomial fast.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/synthetic-division-ruffini/Content licensed under CC BY-NC 4.0.