2009-06-30 8 views
3

私はsrandom()とrandom()を使って、Unixシステム上でcで乱数を生成しています。私は複数のRNGを持っていたいと思います。同じシードを与えられたそれぞれは、同じシーケンスを出力する必要があります。私はまた、それぞれの状態を保存して復元したいと思います。擬似コードの例を次に示します。c/Unixの複数の乱数ジェネレータの状態

R1 = new_rng(5); //5 is the seed 
R2 = new rng(5); //5 is the seed here, too. 
a = R1.random(); 
b = R1.random(); 
d = R2.random(); //a == d 
s1 = R2.get_state(); //save the state of R2 
e = R2.random(); //b == e 
R2.set_state(s1); //restore the state of R2 
f = R2.random(); //b == f 

どうすればよいですか? RNGは異なるスレッドに分岐することがあり、新しいスレッドを作成するときにはRNGの状態を複製する必要があります。

+0

まあ、 "醜い"解決策は、シードと何回ランダムが呼び出されたかを保存するクラスを作成し、それを使って状態を復元することです。もちろん、あなたが本当に遅くなるたくさんの数字を使うならば。 –

答えて

6

erand48()/nrand48()/jrand48()を使用すると、倍精度浮動小数点数、負でない長整数、または符号付き長整数乱数をそれぞれ生成できます。これらの関数を使用すると、必要な数の独立したシーケンスを持つことができます。状態は引数として渡され、簡単に保存して復元することができます。さらに、シーケンスは標準によって定義されており、異なるプラットフォームであっても実行によって変化しません。

その他の回答は、rand_r()を提案しています。 drand48()機能がはるかに精巧な乱数ジェネレータを提供し

:この関数は、このノートを含む、POSIX.1-2008で旧式です。

1つの関数呼び出しと別の手段の間で実行できる量の制限は、疑似乱数ジェネレータのすべての要件を満たす方法で実装することはできません。rand_r()したがって、この機能は、安全性を含めた軽微な要求事項が満たされなければならないときは避けなければなりません。

rand_r()機能は、将来のバージョンで削除される可能性があります。

+0

drand48を他の回答)を参照してください: 新しい乱数=古い乱数* A + C は本当に弱虫です!確かにrandom()はそれよりも強かった。 – Eyal

+1

いいえ、実際はありません。多くの "ランダムな"実装は、同様の乗算付き桁上げジェネレータ、または同様の単​​純なLFSRです。 – ephemient

+0

実際はnew_state = old_state * a + cです。状態および算術は48ビットであり、結果は状態の上位ビットから取られる。あなたが強くしたい場合は、暗号で安全な乱数ジェネレータを使用する必要があります。通常、それは遅くなり、保存/復元するために多くのストレージを取る。営業担当者は、再現性と保存/復元能力にもっと関心がありました。 – mark4o

0

私はあなたが実際に同じシードを与えられた正確に同じシーケンスを生成するために、あなたのPRNGに頼ることができるかわかりません。私はいくつかの方法がそのように機能することを知っていますが、より良いものには一定の量の非決定論的なものが含まれていると信じています。あなたは細かい歯のついた櫛でlibcのドキュメントを調べ、どこかで言及されているかどうかを調べる必要があります。そうでない場合は、コードをチェックしてください(コードにアクセスできると幸運な場合)。いずれにしても

、この意志のカップルあなたのlibcのPRNGの実装に確かに非常に密接にあなたのアプリケーション。開発しているlibcの味、そしておそらくlibcのバージョンに縛られることは間違いありません。この機能が非常に重要な場合は、移植性と再現性を確保するために、アプリで乱数生成を再実装する必要があります。

+2

いいえ。 PNRGは毎回同じシーケンスを再現する必要があります。それ以外の方法でデバッグのためのテストを繰り返します。壊れていないPNRG。 – Eyal

1

this article on Mersenne twisterを読んでください。一番下にはいくつかの実装へのリンクがあります。 (言い換えれば、PRNGを自分で実装しています。)

1

さまざまなUNIXフレーバーにいくつかのCライブラリの拡張機能があります:ランダム、チェックinitstate/SETSTATE

  • _rバリアント(random_r、srandom_r、などの

    • BSDは、 initstate_r、など)
    • rand_r(STDLIB.H)ターゲットUNIXでサポートされて味

  • 1

    srand()およびrand()の代わりにrand_r(unsigned *seed)を使用してください。そうすれば、複数のランダムな種子を維持することができます。

    +0

    これはrand_r()は使用すべきではないと言う(とその理由を与える)( – user9876