让我们来看看。
count = 1
i = 3
while count != 1000:
if i%2 != 0:
for k in range(2,i):
if i%k == 0: # 'i' is _not_ a prime!
print(i) # ??
count += 1 # ??
break
i += 1 # should be one space to the left,
# for proper indentation
如果i%k==0
,则i
不是素数。如果我们检测到它不是素数,我们应该(a)不打印出来,(b)不增加找到的素数的计数器,(c)我们确实应该跳出for
循环——不需要测试更多的数字。
i%2
另外,我们可以不用 testing ,而是2
从 开始递增,3
然后它们都将是奇数,通过构造。
所以,我们现在有
count = 1
i = 3
while count != 1000:
for k in range(2,i):
if i%k == 0:
break
else:
print(i)
count += 1
i += 2
如果循环没有过早中断,则执行else
after 。for
for
它可以工作,但是工作太辛苦,因此比必要的要慢得多。它通过它下面的所有数字来测试一个数字,但是仅仅测试它的平方根就足够了。为什么?因为如果一个数字n == p*q
,p
和q
之间1
,n
那么至少有一个p
或q
将不大于 的平方根n
:如果它们都大于 ,则它们的乘积将大于n
。
所以改进的代码是:
from math import sqrt
count = 1
i = 1
while count < 1000:
i += 2
for k in range(2, 1+int(sqrt(i+1))):
if i%k == 0:
break
else:
# print(i) ,
count += 1
# if count%20==0: print ""
print i
试着用range(2,i)
(如前面的代码)运行它,看看它有多慢。对于 1000 个素数,需要 1.16 秒,对于 2000 – 4.89 秒(3000 – 12.15 秒)。但是生成3000 个素sqrt
数只需要 0.21 秒,10,000 个素数需要 0.84 秒,20,000 个素数需要 2.44 秒(与.的增长数量级)。~ n2.1...2.2
~ n1.5
上面使用的算法称为试除法。要使其成为最佳试验部门,还需要进一步改进,即仅通过素数进行测试。可以在此处看到一个示例,它的运行速度提高了大约 3 倍,并且经验复杂度为 .~ n1.3
然后是 Eratosthenes 的筛子,它的速度相当快(对于 20,000 个素数,比上面的“改进代码”快 12 倍,之后还要快得多:它的经验增长顺序是,对于产生素数,测量到n = 1,000,000 个素数):~ n1.1
n
from math import log
count = 1 ; i = 1 ; D = {}
n = 100000 # 20k:0.20s
m = int(n*(log(n)+log(log(n)))) # 100k:1.15s 200k:2.36s-7.8M
while count < n: # 400k:5.26s-8.7M
i += 2 # 800k:11.21-7.8M
if i not in D: # 1mln:13.20-7.8M (n^1.1)
count += 1
k = i*i
if k > m: break # break, when all is already marked
while k <= m:
D[k] = 0
k += 2*i
while count < n:
i += 2
if i not in D: count += 1
if i >= m: print "invalid: top value estimate too small",i,m ; error
print i,m
埃拉托色尼的真正无界、增量、“滑动”筛网速度快了大约 1.5 倍,在此测试的这个范围内。