Числа та спіралі: теорія чисел у пікселях
Прості числа здаються випадковими — та розташуйте цілі числа спіраллю, і прості вишикуються вздовж діагоналей. Послідовність Фібоначчі здається довільною — та соняшники й соснові шишки пакують насіння саме цими числами. Теорія чисел, найдавніша гілка чистої математики, має таємне візуальне життя. Ця стаття переводить решета простих чисел, спіралі та філотаксис від цілих чисел до пікселів за допомогою швидких реалізацій на JavaScript canvas.
1. Прості числа та решето Ератосфена
Просте число — це ціле число, більше за 1, що не має додатних дільників, окрім 1 і самого себе. Решето Ератосфена (≈240 р. до н. е.) — один із найдавніших алгоритмів в історії: послідовно позначте всі кратні 2, 3, 5, …; непозначені числа є простими.
Часова складність: O(N log log N) // напрочуд швидко Просторова складність: O(N)
Внутрішній цикл починається з p² — усі менші кратні p вже вилучені попередніми простими числами. Сегментоване решето зменшує пам'ять до O(√N), обробляючи діапазон дружніми до кешу блоками.
2. Спіраль Улама
Станіслав Улам випадково відкрив спіраль, що носить його ім'я, 1963 року, малюючи каракулі під час конференційної доповіді. Запишіть цілі числа 1, 2, 3, … візерунком спіралі, що розгортається назовні, на квадратній сітці; позначте положення всіх простих чисел; результат показує безпомилкові діагональні лінії простих чисел.
Діагоналі відповідають квадратичним многочленам виду n² + n + 41 (формула Гарді-Рамануджана), які дають непропорційно велику густину простих чисел для малих n. Візуальна структура натякає, що розподіл простих чисел не є суто випадковим — закономірність, що пов'язана з глибокими нерозв'язаними питаннями аналітичної теорії чисел.
3. Функція розподілу простих чисел і PNT
Нехай π(x) позначає кількість простих чисел ≤ x (зверніть увагу: це π не є сталою 3.14…). Теорема про розподіл простих чисел (Адамар і де ла Валле-Пуссен, 1896) стверджує:
Краще наближення: Li(x) = ∫₂^x 1/ln(t) dt (інтегральний логарифм)
|π(x) − Li(x)| ~ √x / (4π) · ln(x) (оцінка Рімана, за припущення RH)
Побудова π(x), x/ln(x) і Li(x) на одному графіку наочно демонструє, як ці три криві відстежують одна одну — і наскільки Li(x) є значно точнішим наближенням.
4. Послідовність Фібоначчі та золотий перетин
Послідовність Фібоначчі 1, 1, 2, 3, 5, 8, 13, 21, … задається рекурентним співвідношенням F(n) = F(n-1) + F(n-2). Відношення сусідніх членів збігається до золотого перетину φ:
lim_{n→∞} F(n+1) / F(n) = φ
Замкнена форма (формула Біне): F(n) = (φⁿ − ψⁿ) / √5 де ψ = (1 − √5)/2 ≈ −0.618
φ алгебраїчно є «найбільш ірраціональним» числом — його зображення ланцюговим дробом [1; 1, 1, 1, …] збігається настільки повільно, наскільки це взагалі можливо. Ця властивість — ключ до розуміння, чому рослини використовують кути Фібоначчі.
5. Філотаксис і спіраль соняшника
Насіння соняшника, луски соснових шишок і пелюстки стокроток розташовані у двох сімействах переплетених спіралей. Кількість спіралей за годинниковою та проти годинникової стрілки майже завжди є сусідніми числами Фібоначчі (13 і 21, 34 і 55, …).
Ця закономірність виникає з простого росту: кожне наступне насіння чи листок розміщується з фіксованим кутовим приростом α відносно попереднього. Оптимальне пакування (кожне насіння якомога далі від сусідів) настає, коли α дорівнює золотому куту:
Еквівалентно: 2π × (2 − φ) радіан = 2π(1 − 1/φ) ≈ 2.399 рад
Будь-яке ірраціональне кратне 360° уникало б точного накладання, але золотий кут ірраціональний у найекстремальнішому сенсі — а отже, густина насіння максимально рівномірна, і утворюються два сімейства спіралей, кількість яких є сусідніми числами Фібоначчі.
6. JavaScript: решета, спіралі та соняшники
Сегментоване решето Ератосфена
// Повертає Uint8Array: sieve[i] = 1, якщо i просте, інакше 0
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('Прості ≤ 1 000 000:', s.reduce((a, v) => a + v, 0)); // 78498
Спіраль Улама на canvas
// Малюємо спіраль Улама заданого розміру на 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); // розмір комірки у px
const isPrime = sieve(N * N);
ctx.fillStyle = '#000'; ctx.fillRect(0, 0, W, H);
ctx.fillStyle = '#f59e0b';
// Обходимо спіраль: праворуч, вгору, ліворуч, вниз, праворуч, …
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++;
}
}
}
Філотаксис соняшника
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)); // золотий кут у радіанах ≈ 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); // радіус пропорційний √i
const theta = gold * i; // приріст на золотий кут
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. Гіпотеза Рімана — побіжний погляд
Дзета-функція Рімана визначається для комплексного s з Re(s) > 1 як:
Ріман показав, як ζ(s) пов'язана з точною формулою для π(x) через нетривіальні нулі — комплексні числа ρ = ½ + it, де ζ(ρ) = 0. Гіпотеза Рімана (1859) припускає, що всі нетривіальні нулі лежать на критичній прямій Re(s) = ½.
Якби це було правдою, це довело б найтугіші можливі межі похибки для функції розподілу простих чисел: |π(x) − Li(x)| < (1/8π) √x ln(x) для всіх x ≥ 2.657. Перевірено, що понад 10¹³ нулів лежать на критичній прямій, але гіпотеза лишається однією із Задач тисячоліття — нерозв'язаною з 1859 року.
Побудова дзета-функції Рімана на критичній прямій як траєкторії на діаграмі Аргана розкриває прекрасну спіральну структуру: комплексні значення ζ(½ + it) обвиваються навколо початку координат, перетинаючи нуль щоразу, коли трапляється нетривіальний нуль.
8. Інші візуалізації теорії чисел
Характери Діріхле та квадратичні лишки
Побудуйте n mod p для різних цілих n уздовж сітки, забарвлюючи комірки залежно від того, чи є результат квадратичним лишком за модулем p. Отримані зображення демонструють вражаючу геометричну симетрію, що корениться в теорії символів Лежандра та L-функцій.
Функція Ейлера (тотієнт)
Побудова функції Ейлера φ(n) — кількості цілих чисел до n, взаємно простих із n — відносно n розкриває хмару з фрактальною структурою густини. Відношення φ(n)/n наближає ймовірність того, що навмання обране ціле число взаємно просте з n.
Послідовності Фарея та дерево Штерна-Брока
Дерево Штерна-Брока розташовує всі додатні дроби у двійковому дереві так, що кожне раціональне число з'являється рівно раз у нескоротному вигляді. Збільшення межі дерева розкриває самоподібну структуру, що відповідає функції-знаку-питання Мінковського — неперервній, строго зростаючій функції, що відображає раціональні числа в діадичні раціональні.