Introduction

Open any spreadsheet of real-world data — city populations, stock prices, river lengths, electricity bills — and count how often each number starts with the digit 1. You might expect roughly 11%, one chance in nine. The actual answer is about 30%.

This is Benford's Law, sometimes called the first-digit law. It says that in many naturally occurring datasets the leading (first) digit is 1 almost a third of the time, the digit 2 about 17.6% of the time, and larger digits are progressively rarer — all the way down to 9, which leads only 4.6% of the time.

The pattern was first noticed in 1881 by the astronomer Simon Newcomb, who observed that the early pages of logarithm tables were more worn than the later ones. The physicist Frank Benford rediscovered and published it in 1938 across twenty different datasets. Today the law bears his name — and it is far more than a curiosity. It is a forensic weapon.

When people fabricate numbers — inflating invoices, padding expense reports, cooking tax returns — they tend to invent "random-looking" figures. They forget about Benford's Law. The result is a digit distribution that looks too uniform, and auditors know exactly what to look for.

Try It

Generate a dataset below and watch the leading-digit distribution stack up against the expected Benford curve (shown in orange). Real data hugs the curve; fabricated data betrays itself.

<p class="hint">Pick a dataset and click <b>Generate</b>. The bars show the leading-digit distribution; the orange dots show Benford's expected curve. Real data follows it — fake data doesn't.</p>
<div class="controls">
  <select id="dataset">
    <option value="powers2">Powers of 2 (2¹ … 2¹⁰⁰⁰)</option>
    <option value="fibonacci">Fibonacci numbers (first 500)</option>
    <option value="populations">Simulated city populations</option>
    <option value="random">Random integers (fake data)</option>
  </select>
  <button id="generate" type="button">Generate</button>
</div>
<div id="chart" class="chart"></div>
<div class="result" id="result"></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 .8rem; line-height: 1.45; }
.controls { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: .8rem; align-items: center; }
select { font: 14px system-ui; padding: .4rem .6rem; border: 1px solid #aaa; border-radius: 8px; background: #fff; color: #222; flex: 1; min-width: 180px; }
button { font: 600 14px system-ui; padding: .45rem 1rem; border: 1px solid #1d3557; background: #1d3557; color: #fff; border-radius: 8px; cursor: pointer; white-space: nowrap; }
.chart { display: flex; align-items: flex-end; gap: 4px; height: 160px; padding: 0 2px; border-bottom: 2px solid #bbb; position: relative; }
.bar-wrap { display: flex; flex-direction: column; align-items: center; flex: 1; height: 100%; justify-content: flex-end; position: relative; }
.bar { width: 100%; border-radius: 4px 4px 0 0; min-height: 2px; background: #457b9d; transition: height .4s ease; position: relative; }
.bar-label { font: 700 11px ui-monospace, monospace; color: #555; margin-top: 3px; }
.dot { position: absolute; width: 10px; height: 10px; border-radius: 50%; background: #e67e22; border: 2px solid #fff; box-shadow: 0 0 0 1px #e67e22; transform: translate(-50%, 50%); z-index: 2; }
.pct { font-size: 10px; color: #1d3557; position: absolute; top: -17px; left: 50%; transform: translateX(-50%); white-space: nowrap; }
.result { font-size: .95rem; font-weight: 600; margin-top: .6rem; min-height: 1.3em; color: #1d3557; }
.result.close { color: #0a7d33; }
.result.far { color: #c92f3c; }
.legend { display: flex; gap: 1rem; font-size: .8rem; color: #555; margin-bottom: .4rem; flex-wrap: wrap; }
.legend span { display: flex; align-items: center; gap: 4px; }
.swatch { width: 14px; height: 14px; border-radius: 3px; display: inline-block; }
.swatch.bar-color { background: #457b9d; }
.swatch.dot-color { background: #e67e22; border-radius: 50%; }
const fmt = (s, v) => s.replace(/%(\w+)%/g, (_, k) => String(v[k] ?? ''));
// Benford's Law: P(leading digit = d) = log10(1 + 1/d)
// We compare an observed leading-digit distribution to the expected Benford distribution.
// "Closeness" is measured by the sum of absolute deviations (L1 distance).

const BENFORD = [1,2,3,4,5,6,7,8,9].map(d => Math.log10(1 + 1/d));

function leadingDigit(n) {
  const s = String(Math.abs(Math.round(n)));
  for (const ch of s) { const d = parseInt(ch); if (d > 0) return d; }
  return null;
}

// --- Dataset generators ---
function powersOf2() {
  const out = [];
  let v = 1n;
  for (let i = 0; i < 1000; i++) { out.push(Number(String(v).slice(0, 10))); v *= 2n; }
  return out;
}

function fibonacci() {
  const out = [];
  let a = 1n, b = 1n;
  for (let i = 0; i < 500; i++) {
    out.push(Number(String(a).slice(0, 10)));
    [a, b] = [b, a + b];
  }
  return out;
}

function simulatedPopulations() {
  // Lognormal distribution approximates city populations
  const out = [];
  for (let i = 0; i < 1000; i++) {
    // Box-Muller for normal, then exponentiate
    const u1 = Math.random(), u2 = Math.random();
    const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
    const pop = Math.round(Math.exp(z * 1.8 + 10)); // mean ~22000, wide spread
    if (pop > 0) out.push(pop);
  }
  return out;
}

function randomIntegers() {
  const out = [];
  for (let i = 0; i < 1000; i++) out.push(Math.floor(Math.random() * 9000) + 1000);
  return out;
}

function getDataset(name) {
  switch (name) {
    case 'powers2': return powersOf2();
    case 'fibonacci': return fibonacci();
    case 'populations': return simulatedPopulations();
    case 'random': return randomIntegers();
    default: return powersOf2();
  }
}

function computeFrequencies(data) {
  const counts = new Array(10).fill(0);
  let total = 0;
  for (const n of data) {
    const d = leadingDigit(n);
    if (d !== null && d >= 1 && d <= 9) { counts[d]++; total++; }
  }
  return counts.slice(1).map(c => total > 0 ? c / total : 0);
}

function l1Distance(a, b) {
  return a.reduce((s, v, i) => s + Math.abs(v - b[i]), 0);
}

function render(observed) {
  const chart = document.getElementById('chart');
  const maxVal = Math.max(...observed, ...BENFORD) * 1.15;
  chart.innerHTML = '';
  observed.forEach((freq, i) => {
    const d = i + 1;
    const benfordFrac = BENFORD[i];
    const wrap = document.createElement('div');
    wrap.className = 'bar-wrap';

    const bar = document.createElement('div');
    bar.className = 'bar';
    const barPct = (freq / maxVal) * 100;
    bar.style.height = barPct + '%';

    const pct = document.createElement('div');
    pct.className = 'pct';
    pct.textContent = (freq * 100).toFixed(1) + '%';
    bar.appendChild(pct);

    // Benford dot positioned relative to chart height
    const dot = document.createElement('div');
    dot.className = 'dot';
    const dotBottom = (benfordFrac / maxVal) * 160; // 160px = chart height
    dot.style.bottom = dotBottom + 'px';
    dot.style.left = '50%';

    const label = document.createElement('div');
    label.className = 'bar-label';
    label.textContent = d;

    wrap.appendChild(bar);
    wrap.appendChild(dot);
    wrap.appendChild(label);
    chart.appendChild(wrap);
  });
}

function setResult(observed, datasetName) {
  const dist = l1Distance(observed, BENFORD);
  const el = document.getElementById('result');
  // L1 distance < 0.05 is very close; > 0.2 is clearly non-Benford
  if (datasetName === 'random') {
    el.className = 'result far';
    el.textContent = fmt('Fake data: L1 distance from Benford = %dist% — distribution is too flat.', { dist: dist.toFixed(3) });
  } else if (dist < 0.07) {
    el.className = 'result close';
    el.textContent = fmt('Close match! L1 distance from Benford = %dist% — follows the law well.', { dist: dist.toFixed(3) });
  } else {
    el.className = 'result';
    el.textContent = fmt('L1 distance from Benford = %dist%.', { dist: dist.toFixed(3) });
  }
  console.log('Dataset:', datasetName, '| L1 distance from Benford:', dist.toFixed(4),
    '| Observed:', observed.map(x => (x*100).toFixed(1)+'%').join(', '));
}

// Add legend
const legend = document.createElement('div');
legend.className = 'legend';
legend.innerHTML = '<span><span class="swatch bar-color"></span>Observed frequency</span><span><span class="swatch dot-color"></span>Benford expected</span>';
document.getElementById('chart').before(legend);

document.getElementById('generate').addEventListener('click', () => {
  const name = document.getElementById('dataset').value;
  const data = getDataset(name);
  const observed = computeFrequencies(data);
  render(observed);
  setResult(observed, name);
});

// Initial render with powers of 2
(function() {
  const data = powersOf2();
  const observed = computeFrequencies(data);
  render(observed);
  setResult(observed, 'powers2');
})();
Result
Console

Notice how real datasets (powers of 2, city populations, Fibonacci numbers) closely follow the curve, while random integers produce a nearly flat distribution. The gap between them is exactly what a fraud examiner measures.

The Math Behind It

Benford's Law is not a coincidence — it follows from a clean mathematical argument about scale invariance.

Suppose a law of nature governs some quantity x. If that law is truly scale-invariant — meaning it looks the same whether you measure in meters or feet, dollars or euros — then the distribution of x must be such that the proportion of values starting with digit d depends only on d and not on the units. The only distribution with this property is the logarithmic one:

P(leading digit=d)=log⁡10 ⁣(1+1d)P(\text{leading digit} = d) = \log_{10}\!\left(1 + \frac{1}{d}\right)

Plugging in the numbers: d=1d = 1 gives log⁡10(2)≈30.1%\log_{10}(2) \approx 30.1\%, d=2d = 2 gives log⁡10(3/2)≈17.6%\log_{10}(3/2) \approx 17.6\%, …, d=9d = 9 gives log⁡10(10/9)≈4.6%\log_{10}(10/9) \approx 4.6\%.

This was rigorously proved in 1995 by Theodore Hill (Georgia Tech). Hill showed that if you randomly mix distributions — drawing from stock prices, populations, and areas all at once — the resulting mixture converges to Benford's Law almost surely. The theorem explains why the law holds across such wildly different datasets: any process that multiplies and mixes independent quantities will tend to produce it.

Benford's Law does not apply to everything. It fails when data is artificially bounded (e.g., human heights between 150–200 cm), when it comes from a narrow range, or when it is assigned sequentially (phone numbers, social security numbers). A forensic examiner must understand the domain before declaring fraud.

Compare it to another mathematical pattern in data: the birthday paradox, where coincidences appear far sooner than intuition suggests — in both cases, our gut instinct about randomness is systematically wrong.

Where It Matters

Benford's Law is one of the few mathematical theorems that has been admitted as evidence in court. Its applications span:

  • Forensic accounting: the IRS and accounting firms run Benford tests on expense reports, invoice totals, and tax filings as a first-pass screen for manipulation. Values around $1,000, $5,000 or $10,000 are red flags — people round to comfortable numbers and avoid leading 1s.
  • Election integrity: after several disputed elections, researchers applied Benford's Law to precinct-level vote totals. Results are contested (election data may not satisfy the distributional prerequisites), but the technique entered public debate and spurred rigorous methodological work.
  • Scientific data integrity: several academic fraud cases were opened after Benford analysis of reported measurements revealed too-uniform digit distributions, inconsistent with genuine experimental noise.
  • Computer science and data generation: random number generators can be tested against Benford's Law; a generator that produces too-uniform leading digits for naturally-scaled quantities has a bias.
  • Macroeconomic analysis: researchers used Benford's Law to assess the reliability of economic statistics reported by different countries, finding deviations correlated with governance quality.

The common thread: wherever humans invent numbers that should obey a natural distribution, they unconsciously break Benford's Law. Knowing the expected distribution turns human psychology into a forensic signature. See also P vs NP — another case where our intuitions about what is "easy" or "random" clash sharply with mathematical reality.

Conclusion

Benford's Law is one of mathematics' most counterintuitive gifts: a simple formula — log⁡10(1+1/d)\log_{10}(1 + 1/d) — that predicts how often each digit leads in almost any naturally generated dataset. It emerges not from magic but from scale invariance and the mathematics of logarithms, and it was rigorously proved by Hill in 1995.

Its power lies in human psychology. When people fabricate numbers, they aim for "random" — and they overshoot, producing distributions that are too uniform. Benford's Law turns that overcorrection into a measurable signal. It has been accepted in U.S. federal court, used to flag billions of dollars in suspicious transactions, and applied to election results and scientific publications worldwide.

The next time you stare at a column of numbers, you are looking at a dataset that almost certainly carries Benford's fingerprint — and any fraudster who forgot that has already given themselves away.

Share this article

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

Comments

Loading comments...

https://www.kipuhub.com/en/article/benfords-law/Content licensed under CC BY-NC 4.0.