Давайте рассмотрим это шаг за шагом.
Eins = np.ones(n, dtype=bool)
Это создает новый массив размером n с типом bool
и всеми единицами. Из-за типа «один» означает True
. Массив представляет все наши числа, которые мы хотим проверить на простоту, где True
означает, что число простое, а False
— нет. Итак, мы начинаем со всех чисел, помеченных как (потенциальные) простые числа.
Eins[0] = Eins[1] = False
Теперь мы устанавливаем элементы 0
th и 1
st равными False
: ни 0, ни 1 не являются простыми числами.
for i in range(2, n):
Далее мы перебираем все оставшиеся числа (начиная с 2). Мы могли бы обойтись только поиском квадратного корня из n, но для простоты мы просматриваем все числа.
if Eins[i]:
Если i
th значение массива равно True
, это означает, что i
является простым числом. В первый раз это условие будет введено с i=2
. Затем мы хотим удалить все кратные нашему числу из простых кандидатов:
Eins[i*i::i] = False
Мы можем прочитать эту строку так, как если бы она была Eins[2*i::i] = False
, начиная с i*i
— это просто оптимизация¹. Если 2 — простое число, это означает, что 2*2, 3*2, 4*2, ... нет, поэтому мы устанавливаем кратные False
. Обозначение индексации означает «от i*i
до конца» (представлено пустым пространством между двоеточиями) «с шагом i
». Этот оператор производит числа i*i
, i*(i+1)
, i*(i+2)
, ..., то есть все числа, кратные i
, которые еще не помечены как "не простые".
return np.flatnonzero(Eins)
И это просто возвращает все индексы, где значение равно True
, то есть все простые числа, которые были найдены.
1: Несколько слов о i*i
: Мы можем начать с квадрата i
, потому что любые числа j*i
(для j < i
) уже были помечены как непростые, когда мы были в j
.
Вот демонстрация того, что это работает для n=15
:
Начнем с массива, заполненного .ones
:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
[T, T, T, T, T, T, T, T, T, T, T, T, T, T, T]
Затем мы очищаем Eins[0]
и Eins[1]
:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
[F, F, T, T, T, T, T, T, T, T, T, T, T, T, T]
И теперь мы начинаем перебирать диапазон, начиная с i=2
, и удаляем все числа, кратные 2, начиная с 2*2=4
:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
[F, F, T, T, F, T, F, T, F, T, F, T, F, T, F]
i=3
, удаляя все числа, кратные 3, начиная с 3*3=9
:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
[F, F, T, T, F, T, F, T, F, F, F, T, F, T, F]
Обратите внимание, что нам не нужно было удалять 6
, потому что он уже был удален i=2
.
Когда i=4
, мы пропускаем удаление, потому что Eins[i]
это False
. Начиная с i=5
ничего не происходит, потому что квадраты (25, 36,...) больше, чем массив. Наконец, мы используем flatnonzero
и получаем все индексы, где значение равно True
:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
[F, F, T, T, F, T, F, T, F, F, F, T, F, T, F]
2 3 5 7 11 13
person
L3viathan
schedule
12.11.2018
Eins[0] = Eins[1] = False
: потому что 0 и 1 не являются простыми числами. - person 9769953   schedule 12.11.2018if Eins[i]: Eins[i*i::i] = False
: еслиi
число равно False (= не простое), установите его квадрат и каждое i-е последующее число как False/не простое. Это часть сита. - person 9769953   schedule 12.11.2018flatnontzero
правильно задокументирован: он возвращает (сглаженный ) индексы ненулевых (неложных, не простых) чисел. Поскольку мы используем индексы как фактические числа для проверки сита, это дает простые числа. - person 9769953   schedule 12.11.2018