64ビットLCG(MMIX(by Knuth))を使用しています。コード内に特定の乱数ブロックを生成し、それらを使用していくつかの操作を実行します。私のコードはシングルコアで動作し、実行時間を短縮するために作業を並列化したいと思います。
この意味でより高度な方法を考える前に、より多くの同一のコードを並行して実行したいと思います(実際、コードは特定の数の独立したシミュレーションで同じタスクを繰り返すので、シミュレーションの数をより多くのシミュレーションに分割できます同一のコードを並行して実行します)。
私の唯一の問題は、各コードのシードを見つけることです。特に、異なるコードで生成されたデータ間の望ましくない重要な相関の可能性を回避するために、さまざまなコードで生成された乱数が重複しないようにする必要があります。そうするために、最初のコードの特定のシードから始めて、絶対値ではなく疑似ランダムシーケンスで非常に離れた値(次のシード)を見つける方法を見つける必要があります(つまり、最初のシードから2番目のシードまで、LCGの膨大な数のステップが必要です)。
私の最初の試みはこれでした:
シーケンスで生成された2つの連続した数の間のLCG関係から始めます
したがって、原則として、たとえばn = 2 ^ 40およびI_0が最初のシードの値に等しい場合に上記の関係を計算し、最初のシードからランダムCLGシーケンスで2 ^ 40ステップ離れた新しいシードを取得できます。 。
問題は、そうすることで、a ^ nを計算してオーバーフローする必要があるということです。実際、MMIX(Knuthによる)a〜2 ^ 62の場合、unsigned long long int(64ビット)を使用します。ここでの唯一の問題は、上記の関係の分数であることに注意してください。合計と乗算しかない場合は、次のモジュラープロパティによるオーバーフローの問題を無視できます(実際、c(64ビットジェネレーター)として2 ^ 64を使用しています)。
それで、特定の値(最初のシード)から始めて、LC疑似ランダムシーケンスの膨大な数のステップから離れた2番目の値をどのように見つけることができますか?
フォームのLCGは、x[n+1] = (x[n] * a + c) % m
任意の位置にすばやくスキップできます。
ゼロのシード値から始めて、LCGの最初の数回の反復で次のシーケンスが得られます。
x₀ = 0
x₁ = c % m
x₂ = (c(a + 1)) % m
x₃ = (c(a² + a + 1)) % m
x₄ = (c(a³ + a² + a + 1)) % m
各項が実際には等比数列の合計であることが非常に簡単にわかります。これは簡単な式で計算できます。
x_n = (c(a^{n-1} + a^{n-2} + ... + a + 1)) % m
= (c * (a^n - 1) / (a - 1)) % m
(a^n - 1)
用語により迅速に算出することができるべき乗剰余が、で除算する(a-1)
ので、ビットトリッキーである(a-1)
とm
我々は計算できないので、両方であっても(すなわち、互いに素ではない)であるモジュラ逆数の(a-1) mod m
直接の。
代わりに、を計算して(a^n-1) mod m*(a-1)
から、結果の単純な(非モジュラー)除算を実行しa-1
ます。Pythonでは、計算は次のようになります。
def lcg_skip(m, a, c, n):
# Calculate nth term of LCG sequence with parameters m (modulus),
# a (multiplier) and c (increment), assuming an initial seed of zero
a1 = a - 1
t = pow(a, n, m * a1) - 1
t = (t * c // a1) % m
return t
def test(nsteps):
m = 2**64
a = 6364136223846793005
c = 1442695040888963407
#
print("Calculating by brute force:")
seed = 0
for i in range(nsteps):
seed = (seed * a + c) % m
print(seed)
#
print("Calculating by fast method:")
# Calculate nth term by modular exponentiation
print(lcg_skip(m, a, c, nsteps))
test(1000000)
したがって、出力シーケンスが重複しないLCGを作成するには、によって生成された初期シード値を使用するだけlcg_skip()
で、n
その値は十分に離れています。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加