Решето Эратосфена (sieve of Eratosthenes) находит все простые числа от 2 до N за : каждое найденное простое вычёркивает свои кратные.

Зачем нужно

Задача: N — натуральное число, найти все простые .

Не из лекции: сравнение с проверкой по одному

Проверить одно число на простоту можно за — см. L01. Если проверять так каждое число до N, выйдет . Решето не проверяет числа по одному, а сразу вычёркивает все составные — почти линейно.

Как работает

Таблица is_prime на элемент, сначала всё ✓, 0 и 1 — ✗. Идём по :

  • is_prime[d] = ✗ — составное, пропускаем;
  • is_prime[d] = ✓ — простое, вычёркиваем .
is_prime = [T, T, ..., T]              // N + 1 элемент
is_prime[0] = is_prime[1] = F
for d = 2 ... N
    если is_prime[d] = T               // d — простое
        m = 2
        while (m * d ≤ N)
            is_prime[m * d] = F
            m++
for d = 2 ... N
    если is_prime[d] = T
        print(d)

Здесь 2 ... N включает N.

Почему верно

Не из лекции: корректность

Вычёркиваются только числа с — составные. Любое составное вычеркнет его наименьший делитель : этот делитель простой, и при нём дойдёт до .

Когда цикл доходит до , is_prime[d] уже окончательный: если составное, его наименьший простой делитель меньше и уже успел его вычеркнуть. Алгоритм опирается на таблицу, которую сам же строит.

Оценки

На лекции: , без доказательства.

Не из лекции: откуда и память

Для простого внутренний цикл делает меньше шагов, поэтому . Сумма обратных простых растёт как . Доказательство — в конспекте L03.

Если бы вычёркивали кратные каждого , а не только простого, получилось бы .

Память — таблица на элемент: .

Тонкости

  • растёт очень медленно: при это около 2,9. На практике решето работает почти как линейный проход.
  • Память — ограничение: решето до требует гигабайт таблицы (по байту на число).
  • Проверку is_prime[d] нельзя убирать: без неё составные тоже вычёркивали бы кратные, и время выросло бы до . Ответ при этом остался бы верным.

Частые ошибки

  • Таблица на N элементов вместо : само N не помещается.
  • Забыть is_prime[0] = is_prime[1] = F — 0 и 1 окажутся «простыми».
  • Цикл вывода for d = 2 ... N без самого N — простое N потеряется.