Оптимизируйте сито эратосфенов далее

Я написал сито Эратосфена - я думаю, но похоже, что оно не так оптимизировано, как могло бы быть. Он работает, и он получает все простые числа до N, но не так быстро, как я надеялся. Я все еще изучаю Python - начиная с двух лет Java - так что если что-то не особенно Pythonic, то я извиняюсь:

def sieve(self):
        is_prime = [False, False, True, True] + [False, True] * ((self.lim - 4) // 2)
        for i in range(3, self.lim, 2):
            if i**2 > self.lim: break
            if is_prime[i]:
                for j in range(i * i, self.lim, i * 2):
                    is_prime[j] = False
        return is_prime

Я рассмотрел другие вопросы, подобные этому, но я не могу понять, как некоторые из более сложных оптимизаций будут вписываться в мой код. Любые предложения?

EDIT: по запросу некоторые из других оптимизаций, которые я видел, останавливают итерацию первого цикла цикла до предела и пропускают разные числа - что я считаю оптимизацией колес?

EDIT 2: Здесь код, который будет использовать этот метод, для Padraic:

primes = sieve.sieve()
for i in range(0, len(primes)):
    if primes[i]:
        print("{:d} ".format(i), end = '')
print() # print a newline

Ответ 1

несколько иной подход: используйте bitarray для представления нечетных чисел 3,5,7,..., сохраняя некоторое пространство по сравнению со списком логических элементов.

это может сэкономить только некоторое пространство, а не ускорить...

from bitarray import bitarray

def index_to_number(i): return 2*i+3
def number_to_index(n): return (n-3)//2

LIMIT_NUMBER = 50
LIMIT_INDEX = number_to_index(LIMIT_NUMBER)+1

odd_primes = bitarray(LIMIT_INDEX)
# index  0 1 2 3
# number 3 5 7 9

odd_primes.setall(True)

for i in range(LIMIT_INDEX):
    if odd_primes[i] is False:
        continue
    n = index_to_number(i)
    for m in range(n**2, LIMIT_NUMBER, 2*n):
        odd_primes[number_to_index(m)] = False

primes = [index_to_number(i) for i in range(LIMIT_INDEX)
          if odd_primes[i] is True]
primes.insert(0,2)

print('primes: ', primes)

та же идея снова; но на этот раз пусть битаррей обрабатывает внутренний цикл, используя назначение среза. это может быть быстрее.

for i in range(LIMIT_INDEX):
    if odd_primes[i] is False:
        continue
    odd_primes[2*i**2 + 6*i + 3:LIMIT_INDEX:2*i+3] = False

(никто из этого кода не был серьезно проверен! используйте с осторожностью)


если вы ищете генератор простых чисел, основанный на другом методе (wheel factorizationition), посмотрите этот отличный ответ.