Numbers & Spirals: Number Theory in Pixels
Prime numbers look random — yet arrange the integers in a spiral and primes align along diagonals. The Fibonacci sequence looks arbitrary — yet sunflowers and pine cones pack seeds using exactly those numbers. Number theory, the oldest branch of pure mathematics, has a secret visual life. This article takes prime sieves, spirals, and phyllotaxis from integers to pixels with fast JavaScript canvas implementations.
1. Primes and the Sieve of Eratosthenes
A prime number is an integer greater than 1 with no positive divisors other than 1 and itself. The Sieve of Eratosthenes (≈240 BCE) is one of the oldest algorithms in existence: mark all multiples of 2, 3, 5, … in sequence; the unmarked numbers are prime.
Time complexity: O(N log log N) // remarkably fast Space complexity: O(N)
The inner loop starts at p² — all smaller multiples of p were already eliminated by earlier primes. The segmented sieve reduces memory to O(√N) by processing the range in cache-friendly blocks.
2. The Ulam Spiral
Stanisław Ulam discovered the spiral bearing his name by accident in 1963, doodling during a conference talk. Write the integers 1, 2, 3, … in an outward-going spiral pattern on a square grid; mark the positions of all prime numbers; the result shows unmistakeable diagonal lines of primes.
The diagonals correspond to quadratic polynomials of the form n² + n + 41 (Hardy-Ramanujan formula) which produce a disproportionate density of primes for small n. The visual structure hints that prime distribution is not purely random — a pattern which connects to deep unresolved questions in analytic number theory.
3. Prime-Counting Function and the PNT
Let π(x) denote the number of primes ≤ x (note: this π is not the constant 3.14…). The Prime Number Theorem (Hadamard & de la Vallée Poussin, 1896) states:
Better approximation: Li(x) = ∫₂^x 1/ln(t) dt (logarithmic integral)
|π(x) − Li(x)| ~ √x / (4π) · ln(x) (Riemann's estimate, assuming RH)
Plotting π(x), x/ln(x), and Li(x) together visually demonstrates how the three curves track each other — and how Li(x) is a much tighter approximation.
4. Fibonacci Sequence and the Golden Ratio
The Fibonacci sequence 1, 1, 2, 3, 5, 8, 13, 21, … is defined by the recurrence F(n) = F(n-1) + F(n-2). The ratio of consecutive terms converges to the golden ratio φ:
lim_{n→∞} F(n+1) / F(n) = φ
Closed form (Binet formula): F(n) = (φⁿ − ψⁿ) / √5 where ψ = (1 − √5)/2 ≈ −0.618
φ is algebraically the "most irrational" number — its continued fraction representation [1; 1, 1, 1, …] converges as slowly as possible. This property is key to understanding why plants use Fibonacci angles.
5. Phyllotaxis and the Sunflower Spiral
Sunflower seeds, pine cone scales, and daisy petals are arranged in two families of interlocking spirals. The number of clockwise and counter-clockwise spirals are almost always consecutive Fibonacci numbers (13 and 21, 34 and 55, …).
This pattern arises from simple growth: each successive seed or leaf is placed at a fixed angular increment α relative to the previous one. The optimal packing (each seed as far as possible from its neighbours) occurs when α equals the golden angle:
Equivalently: 2π × (2 − φ) radians = 2π(1 − 1/φ) ≈ 2.399 rad
Any irrational multiple of 360° would avoid exact overlap, but the golden angle is irrational in the most extreme sense — meaning the density of seeds is maximally uniform and two families of spirals form whose counts are consecutive Fibonacci numbers.
6. JavaScript: Sieves, Spirals, and Sunflowers
Segmented Sieve of Eratosthenes
// Returns a Uint8Array: sieve[i] = 1 if i is prime, 0 otherwise
function sieve(N) {
const s = new Uint8Array(N + 1).fill(1);
s[0] = s[1] = 0;
for (let p = 2; p * p <= N; p++)
if (s[p])
for (let j = p * p; j <= N; j += p) s[j] = 0;
return s;
}
const s = sieve(1_000_000);
console.log('Primes ≤ 1 000 000:', s.reduce((a, v) => a + v, 0)); // 78498
Ulam Spiral on Canvas
// Draw an Ulam spiral of given size on a canvas
function drawUlam(canvas, N) {
const W = canvas.width, H = canvas.height;
const ctx = canvas.getContext('2d');
const cs = Math.floor(Math.min(W, H) / N); // cell size in px
const isPrime = sieve(N * N);
ctx.fillStyle = '#000'; ctx.fillRect(0, 0, W, H);
ctx.fillStyle = '#f59e0b';
// Walk the spiral: right, up, left, down, right, …
const dirs = [[1,0],[0,-1],[-1,0],[0,1]];
let x = Math.floor(N / 2), y = Math.floor(N / 2), d = 0, seg = 1, step = 0, turn = 0;
for (let n = 1; n <= N * N; n++) {
if (isPrime[n]) ctx.fillRect(x * cs, y * cs, cs, cs);
x += dirs[d][0]; y += dirs[d][1]; step++;
if (step === seg) {
step = 0; d = (d + 1) % 4; turn++;
if (turn % 2 === 0) seg++;
}
}
}
Sunflower Phyllotaxis
function drawSunflower(canvas, nSeeds = 1000, c = 6) {
const ctx = canvas.getContext('2d');
const cx = canvas.width / 2;
const cy = canvas.height / 2;
const gold = Math.PI * (3 - Math.sqrt(5)); // golden angle in radians ≈ 2.3998
ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < nSeeds; i++) {
const r = c * Math.sqrt(i); // radius proportional to √i
const theta = gold * i; // golden angle increment
const x = cx + r * Math.cos(theta);
const y = cy + r * Math.sin(theta);
const rad = Math.max(1.5, Math.sqrt(i) * 0.1);
ctx.beginPath(); ctx.arc(x, y, rad, 0, Math.PI * 2);
ctx.fillStyle = `hsl(${40 + i * 0.04}, 90%, 65%)`;
ctx.fill();
}
}
7. The Riemann Hypothesis — a Glimpse
The Riemann zeta function is defined for complex s with Re(s) > 1 as:
Riemann showed how ζ(s) relates to the exact formula for π(x) via the non-trivial zeros — complex numbers ρ = ½ + it where ζ(ρ) = 0. The Riemann Hypothesis (1859) conjectures that all non-trivial zeros lie on the critical line Re(s) = ½.
If true, it would prove the tightest possible error bounds on the prime-counting function: |π(x) − Li(x)| < (1/8π) √x ln(x) for all x ≥ 2.657. More than 10¹³ zeros have been verified to lie on the critical line, but the conjecture remains one of the Millennium Prize Problems — unsolved since 1859.
Plotting the Riemann zeta function on the critical line as an Argand diagram trajectory reveals a beautiful spiral structure: the complex values of ζ(½ + it) wind around the origin, crossing zero whenever a non-trivial zero occurs.
8. Further Number Theory Visualisations
Dirichlet Characters and Quadratic Residues
Plot n mod p for varying integers n along a grid, colouring cells by whether the result is a quadratic residue mod p. The resulting images exhibit striking geometric symmetry rooted in the theory of Legendre symbols and L-functions.
Totient and Euler's Function
Plotting Euler's totient function φ(n) — the count of integers up to n coprime to n — against n reveals a cloud with fractal density structure. The ratio φ(n)/n approximates the probability that a randomly chosen integer is coprime to n.
Farey Sequences and Stern-Brocot Tree
The Stern-Brocot tree arranges all positive fractions in a binary tree such that every rational appears exactly once in lowest terms. Zooming in on the tree boundary reveals self-similar structure corresponding to the Minkowski question-mark function — a continuous, strictly increasing function that maps rationals to dyadic rationals.