どれどれ。
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)見つかった素数のカウンターをインクリメントしないfor
、(c) 実際にループから抜け出す必要があります。これ以上数値をテストする必要はありません。
また、 をテストする代わりに、 から始めてi%2
だけインクリメントすることもできます。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
afterfor
が実行されます。for
動作しますが、あまりにもハードに動作するため、必要以上に遅くなります。それより下のすべての数値で数値をテストしますが、平方根までテストするだけで十分です。なんで?との間の数値n == p*q
がの場合、またはの少なくとも 1 つがの平方根よりも大きくないため、両方が大きければ、それらの積は よりも大きくなります。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 秒) かかります。しかし、 を使用するsqrt
と、3000 個の素数を生成するのに 0.21 秒しかかからず、10,000 個の素数の生成に 0.84 秒、20,000 個の素数の生成に 2.44 秒かかります (対の増加の順序)。~ n2.1...2.2
~ n1.5
上記で使用したアルゴリズムは、試行分割として知られています。最適な試行区分にするために必要なもう 1 つの改善があります。つまり、素数のみによるテストです。例をここで見ることができます。これは、約 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 倍高速です。