Я знаю, что пост старый, но я сам наткнулся на этот вопрос ... Следующий код основан на очень простой идее: растущее сито Эратосфена.Это решение действительно медленнее, чем лучшие здесь, но его легко понять и оно разработано так, чтобы его можно было читать ...
Я использовал целые числа для хранения результатов сита.В двоичном формате целое число представляет собой список 0
s и 1
s, 0
в позиции i
, если i
не является простым числом, 1
, если это может быть простым числом.Необходимая бесконечность является результатом того, что целые числа Python 3 не ограничены.
def primes():
container, size = 1 << 2, 3 # we start with 0b100 (from right to left: 0 and 1 are not primes, 2 is
last_prime = 1
while True:
prime = next((j for j in range(last_prime+1, size) if container & 1 << j), None) # find the next prime
while not prime:
container, size = expand(container, size, 2**16) # add 65536 cells and sieve the container
prime = next((j for j in range(last_prime+1, size) if container & 1 << j), None)
yield prime
last_prime = prime
Как расширить контейнер?Просто добавьте связку 1
слева от контейнера (в двоичном формате) и просейте их.Это идентично стандартному сита с небольшой разницей.В стандартном сите, если мы находим простое число i
, мы начинаем пересекать ячейки в i*i
с шагом i
.
Здесь это может быть сделано для первой частиконтейнера.Нам просто нужно начать с начала новой части контейнера, если она дальше, чем i*i
.
def expand(container, size, n):
new_size = size + n
container += (1 << (new_size + 1) - 1) - (1 << size) # add n 1's
for i in range(2, new_size):
if container & (1 << i): # i is a prime
t = sum(1 << j for j in range(max(i, size // i)*i, new_size, i)) # set 1 for all mutiple
container &= ~t # cross the cells
return container, new_size
Проверка на миллион простых чисел:
import itertools
assert 78498 == len(list(itertools.takewhile(lambda p: p<1000000, primes())))