「もっと見ていたら…」</h1>
クックブックのerat2
関数はさらに高速化できます (約 20 ~ 25%)。
erat2a
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
erat3
少し余分な空想を気にしない場合は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
関数は、30 を法とするすべての素数 (2、3、5 を除く) が 8 つの数 ( MODULOS
frozenset に含まれる数) になるという事実を利用しています。したがって、最初の 3 つの素数が得られた後、7 から始めて候補のみを処理します。
候補フィルタリングはitertools.compress
関数を使用します。「魔法」はMASK
シーケンスにあります。15 の要素 (関数MASK
によって選択された 30 の数字ごとに 15 の奇数がある) を持ち、 7 から始まるすべての可能な候補に対して。サイクルは関数によって指定されたとおりに繰り返されます。
候補フィルタリングの導入には、チェックという別の変更が必要です。のitertools.islice
1
itertools.cycle
or (x%30) not in MODULOS
erat2
アルゴリズムはすべての奇数を処理しました。erat3
アルゴリズムが r30 候補のみを処理するようになったので、すべてがそのような —false — 候補のみになる可能性があることを確認する必要があります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