プライム3を考えてみましょう。考えられるすべての出力を完全に表現するには、次のように考えてください。
bias + step mod prime
これbias
は単なるオフセットバイアスです。step
はアキュムレータであり(1
たとえば、0, 1, 2
シーケンスになっているだけで、2
結果は0, 2, 4
)になりprime
、順列を生成する素数です。
例えば。の単純なシーケンスは0, 1, 2
...
0 + 0 mod 3 = 0
0 + 1 mod 3 = 1
0 + 2 mod 3 = 2
これらの変数のいくつかを1秒間変更して、(説明のためbias
に)1
とを取ります...step
2
1 + 2 mod 3 = 0
1 + 4 mod 3 = 2
1 + 6 mod 3 = 1
まったく異なるシーケンスを作成したことに気付くでしょう。セット内の数字は繰り返されず、すべての数字が表されます(全単射です)。オフセットとバイアスのそれぞれの固有の組み合わせはprime!
、セットの可能な順列の1つになります。の場合、さまざまな可能なパーミュレーションがあることがprime
わかります。3
6
0,1,2
0,2,1
1,0,2
1,2,0
2,0,1
2,1,0
上記の変数で計算を行うと、同じ情報要件が発生することはありません...
1/3! = 1/6 = 1.66..
...対..。
1/3 (bias) * 1/2 (step) => 1/6 = 1.66..
制限は単純で、bias
範囲内である必要があり、範囲内0..P-1
でstep
ある必要があります1..P-1
(私は機能的に、自分の仕事で算術を使用0..P-2
および追加しているだけです)。1
それ以外は、どんなに大きくてもすべての素数で動作し、2、3の整数を超えるメモリを必要とせずにそれらのすべての可能な一意のセットを並べ替えます(それぞれが技術的に素数自体よりわずかに少ないビットを必要とします)。
このジェネレーターは、素数ではないセットを生成するために使用されることを意図していないことに注意してください。そうすることは完全に可能ですが、タイミング攻撃を引き起こす可能性があるため、セキュリティに敏感な目的にはお勧めしません。
とはいえ、この方法を使用して素数ではないセットシーケンスを生成する場合は、2つの選択肢があります。
まず(そして最も単純で最も安い)、探している設定サイズよりも少し大きい素数を選び、ジェネレーターに属していないものを単に破棄させます。繰り返しになりますが、これがセキュリティに敏感なアプリケーションである場合、これは非常に悪い考えです。
次に(はるかに複雑でコストがかかる)、すべての数値が素数で構成されていることを認識し、複数のジェネレーターを作成して、セット内の各要素の積を生成します。言い換えると、n
ofに6
は、一致する可能性のあるすべてのプライムジェネレーター6
(この場合は2
、3
)が含まれ、順番に乗算されます。これは高価であるだけでなく(数学的にはよりエレガントですが)、タイミング攻撃を導入するため、あまりお勧めできません。
bias
最後に、およびまたは...のジェネレータが必要な場合step
は、同じファミリの別のジェネレータを使用してみませんか:)。突然、真の単純ランダムサンプルの作成に非常に近づきました(これは通常は簡単ではありません)。