既然沒有人還沒有顯示出真正的篩子或解釋, 我會嘗試。
基本方法是從2開始計數並消除2 * 2和2的所有更高倍數(即4,6,8 ...),因爲它們都不是素數。 3在第一輪存活,所以它是總理,現在我們消除3 * 3和3的所有更高的倍數(即9,12,15 ...)。 4個被淘汰,5個倖存下來等。每個素數的平方是一個優化,利用了每個新素數的所有較小倍數將在前幾輪被淘汰的事實。使用這個過程來計算和消除非素數時,只有素數會留下。
這是一個非常簡單的版本,發現它不使用模數師或根:
def primes(n): # Sieve of Eratosthenes
prime, sieve = [], set()
for q in xrange(2, n+1):
if q not in sieve:
prime.append(q)
sieve.update(range(q*q, n+1, q))
return prime
>>> primes(100)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73
79, 83, 89, 97]
上面的簡單的方法是出奇的快,但不利用這一素數只能是奇數的事實。
這是一個基於生成器的版本,比我發現的任何其他版本都快,但在我的機器上n = 10 ** 8時達到Python內存限制。
def pgen(n): # Fastest Eratosthenes generator
yield 2
sieve = set()
for q in xrange(3, n+1, 2):
if q not in sieve:
yield q
sieve.update(range(q*q, n+1, q+q))
>>> timeit('n in pgen(n)', setup="from __main__ import pgen; n=10**6", number=10)
5.987867565927445
這裏有一個稍微慢一些,但更多的內存高效發電機版本:
def pgen(maxnum): # Sieve of Eratosthenes generator
yield 2
np_f = {}
for q in xrange(3, maxnum+1, 2):
f = np_f.pop(q, None)
if f:
while f != np_f.setdefault(q+f, f):
q += f
else:
yield q
np = q*q
if np < maxnum:
np_f[np] = q+q
>>> timeit('n in pgen(n)', setup="from __main__ import pgen; n=10**6", number=10)
7.420101730225724
>>> list(pgen(10))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
測試一個數是素數只是做:
>>> 539 in pgen(539)
False
>>> 541 in pgen(541)
True
下面是一些提示,以這種更高效的內存版本如何工作。它使用dict
來存儲最小的信息,下一個非素數(作爲關鍵字)及其因子(作爲值)。由於在dict
中找到每個非素數,因此將其刪除,並使用相同的因子值添加下一個非主鍵。
你的實現是錯誤的,請嘗試運行一次,看看它是否產生正確的答案。檢查我的答案的變化。 –