@WillNess が示唆しているように、そのサイズの単一のモノリシックふるいを作成するべきではありません。代わりに、セグメント化されたエラトステネスのふるいを使用して、連続したセグメントでふるい分けを実行します。最初のセグメントでは、セグメント内にある各ふるい素数の最小倍数が計算され、ふるい素数の倍数が通常の方法で合成としてマークされます。すべてのふるい素数が使用されると、セグメント内の残りのマークされていない数が素数になります。次に、次のセグメントでは、各ふるい素数の最小倍数は、前のセグメントでふるい分けを終了した倍数であるため、ふるい分けは終了するまで続行されます。
20 のセグメントで 100 から 200 までふるい分ける例を考えてみましょう。5 つのふるい素数は 3、5、7、11、13 です。100 から 120 までの最初のセグメントでは、bitarray には 10 個のスロットがあり、スロット 0 は 101 に対応し、スロットkは 100 + 2*k* + 1 に対応します。スロット 9 は 119 に対応します。セグメント内の最小の 3 の倍数は 105 で、スロット 2 に対応します。スロット 2+3=5 および 5+3=8 も 3 の倍数です。5 の最小の倍数はスロット 2 で 105 であり、スロット 2+5=7 も 5 の倍数です。7 の最小の倍数は 105 です。スロット 2 では、スロット 2+7=9 も 7 の倍数です。
関数primes
は引数lo、hi、およびdeltaを取ります。loとhiは、 lo < hiで偶数でなければならず、loはhiの平方根より大きくなければなりません。セグメント サイズはdeltaの 2 倍です。長さmの配列psには、通常のエラトステネスのふるいで計算された偶数が無視されるため、hiの平方根よりも小さいふるい素数が含まれます。2 は削除されます。配列qsにはふるいへのオフセットが含まれます対応するふるい素数の現在のセグメントの最小倍数の bitarray。各セグメントの後、loはdeltaの2 倍進むため、ふるいbitarrayのインデックスiに対応する数値はlo + 2 i + 1 です。
function primes(lo, hi, delta)
sieve := makeArray(0..delta-1)
ps := tail(primes(sqrt(hi)))
m := length(ps)
qs := makeArray(0..m-1)
for i from 0 to m-1
qs[i] := (-1/2 * (lo + ps[i] + 1)) % ps[i]
while lo < hi
for i from 0 to delta-1
sieve[i] := True
for i from 0 to m-1
for j from qs[i] to delta step ps[i]
sieve[j] := False
qs[i] := (qs[i] - delta) % ps[i]
for i from 0 to delta-1
t := lo + 2*i + 1
if sieve[i] and t < hi
output t
lo := lo + 2*delta
上記のサンプルでは、これは と呼ばれprimes(100, 200, 10)
ます。上記の例でqs
は、最初は [2,2,2,10,8] で、最小の倍数 105、105、105、121、および 117 に対応し、2 番目のセグメントでは [1,2,6,0 にリセットされます。 ,11]、最小倍数 123、125、133、121、および 143 に対応します。
デルタの値は重要です。速度のために、キャッシュメモリに収まる限りデルタをできるだけ大きくする必要があります。言語のライブラリを bitarray に使用して、ふるいの場所ごとに 1 つのビットのみを取得します。ふるい素数を計算するために単純なエラトステネスのふるいが必要な場合は、これが私のお気に入りです。
function primes(n)
sieve := makeArray(2..n, True)
for p from 2 to n step 1
if sieve(p)
output p
for i from p * p to n step p
sieve[i] := False
JavaScriptへの翻訳はお任せします。私のブログで、素数を含むその他のアルゴリズムを参照できます。