最大周期の並列線形合同擬似乱数ジェネレータをシードするにはどうすればよいですか?


8

通常、Cで順次乱数ジェネレータをシードするときは、次の呼び出しを使用します

srand(time(NULL))

次に使用します

rand() mod N

0とN-1の間のランダムな整数を取得します。ただし、これを並行して実行すると、time(NULL)の呼び出しが互いに非常に近いため、最終的にはまったく同じ数になります。

私は線形合同乱数ジェネレーターを使ってみました:

xn+1:=axn+c(modm)a,c,m

私が選択することを知っている、いくつかの大きな整数のためにモジュラス演算子が桁を切り捨てることによって計算することができるので、迅速な結果を生成します。しかし、周期の大きいランダムなシーケンスを並列に生成するシードを確立するのは難しいと思います。次の場合、期間の長さが最大であることを知っています m=2kk

  1. cとmは互いに素である
  2. a-1はmのすべての素因数で割り切れる
  3. mが4の倍数の場合、a-1も4の倍数でなければなりません。

(ソース:ウィキペディア

しかし、どのようにすればすべての乱数ストリームにこの最大の特性があることを確認できますか?MPIに関して、rankおよびを組み込んでsize線形合同法を使用して最大周期を生成するにはどうすればよいですか?ラグのあるフィボナッチまたはメルセンヌツイスターを使用して、より長い並列ランダムストリームを生成する方が簡単でしょうか?


3
補足として、科学計算に線形合同のPRNGを使用することはほぼ確実に望ましくありません。彼らは、1より大きい次元のスペースを適切にサンプリングすることはできません。つまり、平面内のポイントの適切なサンプルを描画することもできません。
dmckee ---元モデレーターの子猫

1
@dmckee:マルサリアの定理は確かに一部の科学計算に関連しいますが、すべての科学計算でLCGを不適格と言っても不当です。高速のPRNGを使用することも同様に重要な場合があり、多くの場合、(原点を通る)スパンするベクトルの数は、サンプル空間をカバーする超平面の数よりも重要です。
ジャックポールソン

2
@dmckee:LCGは正しいかもしれませんが、多くのアプリケーションでは1Dで十分です。
ポール

1
@JackPerhaps私は自分の仕事の性質に偏っていて、それが私が欠陥の性質を特定した理由であることに気づいています。Paul:よく研究されたさまざまなPRNGと、多くのトレードオフ(速度、期間、暗号の安全性、および高次元のタプルを描画する能力)があります。Mersenne Twisterは、手作業でコーディングしたものとROOTのデフォルトのPRNGの両方で使用しています。これは最速ではありませんが、数字を描くことは、私の実行時間に対して一般的にはわずかな貢献です。
dmckee ---元モデレーターの子猫

1
あなたがあれば、別の注意点として、必要あなたは間違いなく使用したくない(速度の理由から、おそらく)のLCのPRNGを使用するようにmod下位ビットをつかむために-とジョナサン・ダーシーが提案され、彼らははるかに少ないランダムです。代わりに、(int)乱数をmaxint / rangeで除算して、必要な範囲を取得します。割り算はかかりますが、別のPRNGに切り替えるよりも、乱数ストリームの品質を改善する方がおそらく安価なオプションです。
マークブース

回答:


9

トリックは、各プロセスのLCGストリームをインターリーブすることですプロセスの場合、LCGを変更しますp

xn+1:=axn+c(modm),

することが

xn+p:=Apxn+Cp(modm),

ここで、と実質的にステップ先にます。元のLCGステップを拡張することで、すばやくそれらを導出できます。ApCpp

xn+2=a(axn+c)+c(modm)=a2xn+(a+1)c(modm),

そして、パターンは、あり、は、数値から始まり、を順次乗算し回追加し、次に乗算した結果、すべてです。Apapmodm,Cp0a1 pcmodm

最後のステップは、各プロセスのストライドLCGが重複しないようにすることです。単純に、ランクでを使用してプロセスを初期化し、個々の周期を持つ並列LCGを準備します。ここで、は元の周期で、はプロセスの数。各プロセスの変更されたLCGが均等に使用される場合、全期間が並行して回復されます。prxrN/pNp

私はこれを約6か月前に(おそらく単純に)実装しました。コードはここにあります


それは興味深いアプローチです。分散方式で単一のLC PRNGストリームからN個のタプルを効果的に取得しています。ウィキペディアで言及されている相関の問題はまだありますが、集中型のPRNGソースの同期オーバーヘッドは必要ありません。これらのストリームの品質が、異なる定数を持つ複数のLC PRNGによって作成されたストリーム間の相関とどのように比較されるのか、興味があります。
マークブース

良いアイデア; これはGPU向けに書かれているようです。
チナサール2013

実装はメモリの一貫性のために調整されていますか?各スレッドに連続した大きなブロックを与え、大きなステップでお互いを飛び越えさせようとすると、よりスムーズに機能すると思いますか?一方、GPUでは、完全にストライドされたバージョンが最適です。
Chinasaur 2013

6

Katzgrabberによる非常に優れたチュートリアル概要の論文、「Scientific Computing:Random Numbers In Scientific Computing:Introduction」には、科学計算用のPRNGのユーザーになりたい人を紹介しています。線形合同ジェネレーターは高速ですが、それで十分です。彼らは短期間で、非常に簡単に失敗する可能性があります。a、c、およびmの間の通常の要件を満たしている場合でも、a、c、およびmの完全に合理的に見える組み合わせは、恐ろしく相関した出力になる可能性があります。

さらに悪いことに、mが2の累乗である一般的なケースでは(mod演算が高速です)、下位ビットの周期はシーケンス全体よりもはるかに短いため、rand()%Nを実行すると、あなたが期待するよりもさらに短い期間があります。

一般的な経験則として、lagged-fibbonacci、MT、およびWELLジェネレーターは、はるかに優れたプロパティを備えていますが、それでもかなり高速です。

並列シードの観点から、ジャックポールソンの方法は、プロセッサ間で均等に分割された明確に定義された数列を提供するため、優れています。それが問題でない場合は、さまざまなPRNGをシードするために適切なことを実行できます。同じ論文は、PIDまたはMPIタスク番号を時間とともにハッシュして、多くの人々が独立して考え出した何かを示唆しています。そこで提案されている特定の式は

long seedgen(void)  {
    long s, seed, pid;

    pid = getpid();
    s = time ( &seconds );

    seed = abs(((s*181)*((pid-83)*359))%104729); 
    return seed;
}

その特定の実装については特に意見はありませんが、一般的なアプローチは確かに妥当です。


私は概要紙が好きです、ありがとう!ウィキペディアまたはクヌースのセミニカルアルゴリズムから適切な値を簡単に選択できること、およびカッツグラバー紙の例は、シフト()。(a,c,m)c=0
ジャックポールソン、2012

それはありますが、a = 106、c = 1283、m = 6075(図2)のあるものでも失敗の山です。しかし、はい、利用可能な既知の優れたトリプルがあります。

@JackPoulson:頭の上からa、c、mを選択しなければならないのは非常に苛立たしいことです。このようにすると、常に非常に短い期間につながるようです。引用してくれてありがとう!KnuthのSeminumicalical Algorithmsを調べます。
ポール

2

通常のシーケンシャルRNGを適切な数のスレッドに分散するための簡単なアイデアは、単一のスレッドでシードを可能な限り高速に進め、1,000程度ごとにのみシードをメモリに送信することです。次に、他の各スレッドにこれらの間隔を空けた参照シードの1つを取得させ、そのブロックの1000の値を処理します。つまり、ブロックの1000シードを再生成し、それらの擬似ランダム描画を生成してから、タスクに関連する他の処理を実行します。

これが機能するのは、それほど多くを計算しないRNG(LCGは確かに1つですが、他の多くはこのカテゴリにあるはずです)の場合、実際のボトルネックがシードをメモリに送信しているためです(おそらくその後の処理も同様です)。メモリに何も送信せずにLCGを実行する場合、全体はCPUレジスタにとどまり、非常に高速でなければなりません。より複雑なRNGの場合でも、L1キャッシュにとどまり、非常に高速である必要があります。

私はLCGでこの非常にシンプルなアプローチを使用しましたが、これはレガシーの理由から維持する必要があります。基本的に、典型的なマルチコアワークステーションでは、最大4〜8スレッドの線形スピードアップが得られます。しかし、今私はジャック・ポールソンの答えから方法を試して、うまくいけばさらに速くなるでしょう:)。

OTOH、私はこの単純なトリックが他の本質的にシーケンシャルなRNGで機能するはずだと思います。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.