これは宿題ではありません、ただ興味があるだけです。
ここでのキーワードは「無限」です。
これを として使用したいのですがfor p in primes()
、これは Haskell の組み込み関数だと思います。
したがって、答えは「ふるいをかけるだけ」という単純なものではありません。
まず、連続する素数がいくつ消費されるかはわかりません。では、一度に 100 個の素数を作り出すことができると仮定します。素数の頻度の公式と同様に、同じふるいアプローチを使用しますか?
私は非同時アプローチを好みます。
読んでくださって(そして書いてくださって;))ありがとうございます!
ベストアンサー1
「もっと先が見えていたら…」
クックブックの関数erat2
はさらに高速化できます (約 20 ~ 25%)。
エラト2a
import itertools as it
def erat2a( ):
D = { }
yield 2
for q in it.islice(it.count(3), 0, None, 2):
p = D.pop(q, None)
if p is None:
D[q*q] = q
yield q
else:
# old code here:
# x = p + q
# while x in D or not (x&1):
# x += p
# changed into:
x = q + 2*p
while x in D:
x += 2*p
D[x] = p
チェックnot (x&1)
はそれが奇数であることを確認しますx
。しかし、両方 q
およびがp
奇数である場合、追加することで、2*p
奇数かどうかのテストとともに手順の半分が回避されます。
エラト3
少し余分な装飾を気にしないのであれば、erat2
次の変更を加えることで 35 ~ 40% 高速化できます (注: 関数のため、Python 2.7 以上または Python 3 以上が必要ですitertools.compress
)。
import itertools as it
def erat3( ):
D = { 9: 3, 25: 5 }
yield 2
yield 3
yield 5
MASK= 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0,
MODULOS= frozenset( (1, 7, 11, 13, 17, 19, 23, 29) )
for q in it.compress(
it.islice(it.count(7), 0, None, 2),
it.cycle(MASK)):
p = D.pop(q, None)
if p is None:
D[q*q] = q
yield q
else:
x = q + 2*p
while x in D or (x%30) not in MODULOS:
x += 2*p
D[x] = p
このerat3
関数は、2、3、5を除くすべての素数を30で割った結果が、frozensetに含まれる8つの数だけになるという事実を利用していますMODULOS
。したがって、最初の3つの素数を生成した後、7から始めて、のみ
候補のフィルタリングにはitertools.compress
関数を使用します。その「魔法」はシーケンスにあります。MASK
シーケンスにはMASK
15 個の要素 (関数によって選択される 30 個の数字ごとに 15 個の奇数がありますitertools.islice
) があり1
、7 から始まるすべての候補に対して が付きます。このサイクルは、itertools.cycle
関数で指定されたとおりに繰り返されます。
候補のフィルタリングの導入には、別の変更、つまりor (x%30) not in MODULOS
チェックが必要です。erat2
アルゴリズムではすべての奇数が処理されましたが、アルゴリズムでは r30 個の候補のみが処理されるようになったため、すべてがそのような (偽の) 候補のみであることerat3
を確認する必要があります。D.keys()
ベンチマーク
結果
Atom 330 Ubuntu 9.10 サーバー、バージョン 2.6.4 および 3.1.1+ の場合:
$ testit
up to 8192
==== python2 erat2 ====
100 loops, best of 3: 18.6 msec per loop
==== python2 erat2a ====
100 loops, best of 3: 14.5 msec per loop
==== python2 erat3 ====
Traceback (most recent call last):
…
AttributeError: 'module' object has no attribute 'compress'
==== python3 erat2 ====
100 loops, best of 3: 19.2 msec per loop
==== python3 erat2a ====
100 loops, best of 3: 14.1 msec per loop
==== python3 erat3 ====
100 loops, best of 3: 11.7 msec per loop
AMD Geode LX Gentoo ホーム サーバー、Python 2.6.5 および 3.1.2:
$ testit
up to 8192
==== python2 erat2 ====
10 loops, best of 3: 104 msec per loop
==== python2 erat2a ====
10 loops, best of 3: 81 msec per loop
==== python2 erat3 ====
Traceback (most recent call last):
…
AttributeError: 'module' object has no attribute 'compress'
==== python3 erat2 ====
10 loops, best of 3: 116 msec per loop
==== python3 erat2a ====
10 loops, best of 3: 82 msec per loop
==== python3 erat3 ====
10 loops, best of 3: 66 msec per loop
ベンチマークコード
モジュールには、、および関数がprimegen.py
含まれています。以下はテスト スクリプトです。erat2
erat2a
erat3
#!/bin/sh
max_num=${1:-8192}
echo up to $max_num
for python_version in python2 python3
do
for function in erat2 erat2a erat3
do
echo "==== $python_version $function ===="
$python_version -O -m timeit -c \
-s "import itertools as it, functools as ft, operator as op, primegen; cmp= ft.partial(op.ge, $max_num)" \
"next(it.dropwhile(cmp, primegen.$function()))"
done
done