Наивная реализация сита будет иметь массив is_prime
, который представляет все n
числа, которые мы хотим проверить. Таким образом, его размер будет n
. Затем для каждого p
мы начинаем с 2*p
и помечаем его как «не простое», затем go до 3*p
, 4*p
, 5*p
и т. Д. c, отмечая каждый как «не простое» ». Так, например, когда p = 2
, мы отмечаем 4, 6, 8, 10, 12 и т.д. c как «не простые». Затем, когда p = 3
, мы отмечаем 6, 9, 12, 15 как «не простые».
Я предлагаю вам реализовать этот алгоритм самостоятельно, чтобы понять, как он работает, прежде чем переходить к реализации. Код, который вы просматриваете, использует некоторые приемы, чтобы уменьшить объем работы. Но чтобы понять эти уловки, вам нужно понять базовый алгоритм.
как они пришли с формулой для размера
Это происходит из решения формулы n = i * 2 + 3
для i
, где n
- наибольшее число, которое мы проверим на простоту. Он дает верхнюю границу значения i
для всех чисел, которые мы хотим проверить.
как они получили p = i * 2 + 3
Это позволяет нам проверять только нечетные числа, начиная с 3. Обратите внимание, что четные числа не простые, поэтому мы можем легко пропустить их с помощью этой формулы.
что делает следующее среднее сито от р ^ 2, где р ^ 2 = (4i ^ 2 + 12i + 9). Индекс в is_prime равен (2i ^ 2 + 6i + 3), потому что is_prime [i] представляет 2i + 3
Обратите внимание, что в нашем простом алгоритме мы отметили 6 и 12 как «не простые» дважды , Мы явно делаем дополнительную работу здесь. Мы можем избежать этой дополнительной работы, осознав, что для p
мы уже пометили все составные числа меньше p^2
как «не простые», когда мы определили каждое простое число меньше p
.
Итак, мы начинать нужно только с p^2
вместо p
. Теперь для p = 2
мы отмечаем 4, 6, 8, 10, 12 и т. Д. c, как и раньше. Но затем для p = 3
мы отмечаем 9, 12, 15, 18 и т. Д. c, избегая двойной работы с маркировкой 6 как «не простой». Для этих двух примеров избегаемая двойная маркировка довольно мала, но по мере увеличения p
эта техника приводит к значительному увеличению производительности.
Что касается формулы p^2 = (4i^2 + 12i + 9)
, вы можете выведите это из того, что мы называем методом FOIL при умножении (2*i+3)*(2*i+3)
. Для вашего кода это на самом деле не имеет значения, потому что если вы делаете p = 2*i + 3
, то вы можете вычислить p*p
напрямую, не беспокоясь о базовых алгебраических c манипуляциях.
почему диапазон j начинается с 2 * i ** 2 + 6 * i + 3
У нас есть p^2 = (4i^2 + 12i + 9)
, и нам нужно найти индекс j
в is_prime
, где p^2 = j * 2 + 3
. Мы устанавливаем их равными и решаем для j
.