我在python中找到了一个示例代码,它给出了n
之前的所有素数但我根本得不到它,它为什么会这样做呢?
我已经阅读了有关Sieve of Eratosthenes的维基百科文章,但根本不知道这是如何运作的。
pp = 2
ps = [pp]
lim = raw_input("Generate prime numbers up to what number? : ")
while pp < int(lim):
pp += 1
for a in ps:
if pp%a==0:
break
else:
ps.append(pp)
print set(ps)
可以理解循环如何工作的解释。
编辑 - 弄清楚代码的全部错误表示25为素数并通过更密集的搜索发现这不是没有筛子,有人可以显示利用python中的筛子并解释它的生成器
答案 0 :(得分:2)
首先,这不是一个筛子。
这是它的工作原理。 pp
是我们要测试的数字。在while循环的每次迭代中,我们遍历所有已知的素数(ps
)并检查它们是否除pp
。如果其中之一,pp
不是素数,我们移动到下一个数字。否则,我们会在继续之前将pp
添加到素数列表中。
pp%a==0
行基本上是说“除pp
时a
的指令为零”,即a
除以pp
和{{1}不是素数。
这一直持续到我们检查的数字大于我们设定的某个上限(pp
)
[编辑:这是一个筛子]
lim
这不是最有效的筛选(更高效的筛选在isPrime = [True for i in range(lim)]
isPrime[0] = False
isPrime[1] = False
for i in range(lim):
if isPrime[i]:
for n in range(2*i, lim, i):
isPrime[n] = False
行中执行,但它会起作用,如果for n in range(2*i, lim, i):
是素数,isPrime[i]
将成立。
答案 1 :(得分:2)
由于还没有人展示真正的筛子或解释它,我会尝试。
基本方法是从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
中找到了每个非素数,它将被删除,并且下一个非素数键将添加相同的因子值。
答案 2 :(得分:1)
上述实施产生了错误的答案。我对代码做了一些更改。
但是,上面的代码是如何工作的。
pp = 2
ps = [pp]
我们知道第一个素数是2,因此,我们生成一个仅包含数字2
的列表。
lim = raw_input("Generate prime numbers up to what number? : ")
上面的行接受用户的输入,它给出了要生成的素数的上限。
while pp < int(lim): # 1
pp += 1 # 2
primeFlag = True # 3
for a in ps: # 4
if pp%a==0:
primeFlag = False
break
if primeFlag: # 5
ps.append(pp)
编号的行做了以下事情。
pp
变量增加1。for
循环遍历ps
中存储的素数列表,并检查当前数字pp
是否可被任何一个数字整除,如果是,则数字不是素数,primeFlag
设置为False
,我们会突破内部for
循环。primeFlag
是True
并且if
语句附加列表ps
与pp
。答案 3 :(得分:1)
该代码试图使用试验分区来产生一系列素数。
要纠正它:
pp = 2
ps = [pp]
lim = raw_input("Generate prime numbers up to what number? : ")
while pp < int(lim):
pp += 1
for a in ps:
if pp%a==0:
break
else: # unindent
ps.append(pp) # this
使其更有效(事实上,最佳)试验部门:
pp = 2
ps = [pp]
lim = raw_input("Generate prime numbers up to what number? : ")
while pp < int(lim):
pp += 1
for a in ps:
if a*a > pp: # stop
ps.append(pp) # early
break
if pp%a==0:
break