11

プログラムの開始時に乱数ジェネレーターを1回だけシードするだけで十分かどうか疑問に思います。乱数を使う関数を書きます。関数内にrand()ジェネレーターをシードすることはありませんが、メインエントリでsrand()の呼び出しを残します。たとえば、私のプログラムは次のようになります。

void func1()
{
    std::cout << "This is func1 " << std::rand() << std::endl;
}

void func2()
{
    std::cout << "This is func2 " << std::rand() << std::endl;
}

int main()
{
    std::srand(std::time(NULL));
    func1();
    func2();
    return 0;
}

そうすることで、メインエントリからシードを簡単にオフに切り替えることができます。これは、プログラムをデバッグするときに役立ちます。シードせずにプログラムを実行するたびに、結果は同じに保たれます。ある乱数が原因で問題が発生した場合、別の乱数のセットを生成すると問題がなくなることがあるので、シードをオフにするこのような単純なメカニズムをお勧めします。

ただし、C ++ 11の新しいランダムユーティリティセットでは、使用する前に乱数ジェネレータをインスタンス化する必要があることに気付きました。(例:default_random_engine)。そして、ジェネレーターを個別にシードする必要があるたびに。新しいジェネレーターが必要になったときはいつでも、ジェネレーターを再シードすることが実際に奨励されているのだろうか。グローバルランダムジェネレーターを作成して、以前と同じように1回だけシードできることは知っていますが、グローバル変数を使用するというアイデアはまったく好きではありません。そうしないと、ローカルの乱数ジェネレーターを作成すると、デバッグなどの目的でシードをグローバルにオフにする機能が失われます。

C ++ 11の新機能を学ぶことにワクワクしていますが、非常に混乱する場合があります。新しいランダムジェネレーターに問題があった場合、誰かに知らせてもらえますか?または、C ++ 11のベストプラクティスは何でしょうか?

4

2 に答える 2

18

これは、開発しているシステムの全体的な目標によって異なりますが、一般に、乱数ジェネレーター (RNG) を必要とするシステムは、そのシステムの初期化時に 1 回だけシードする必要があります。

ゲーム開発では、システム (AI、手続き型コンテンツ ジェネレーター、パーティクルなど) ごとに個別の RNG を使用して、デバッグとメンテナンスのためにそのシステムを分離するのが一般的です。

シードを保存すると、ごくわずかなデータ (各フレームからのデルタ入力のみが必要) でロジックを再生することもできます。これにより、アプリケーションのデバッグが容易になるだけでなく、ユーザーの記録および再生機能をサポートすることもできます。リプレイ モードを作成する場合は、明らかに、各リプレイ セッションの前に、各システムの記録されたシードをシステムに提供する必要があります。

定期的に新しいシードを確立したい暗号化などの他のシステムがあります。時間の経過とともにシードを期限切れにするか、クライアント アプリケーションとのハンドシェイクごとに新しいシードを生成する必要がある場合があります。ただし、独自のものよりもはるかに堅牢である可能性が高いため、Cryptography ライブラリを利用することをお勧めします。

于 2013-03-03T06:34:47.320 に答える
7

乱数ジェネレーター (RNG) にインスタンス化が必要な理由の 1 つは、その状態を内部に保持できるようにするためです。マルチスレッド アプリケーションでは、複数のスレッドがプロセスで同じ RNG を使用するときに非決定論を導入しません。 -グローバルな状態。2 つのスレッドがあり、それぞれが問題の独立した部分に取り組んでいるとします。状態 (シード) が RNG インスタンスに対してプライベートである場合、各スレッドの RNG に既知の値をシードすると、決定論を持つことができます。一方、RNG がグローバル変数に状態を保持する場合、各スレッドによって観察される乱数のシーケンスは、RNG への呼び出しのインターリーブに依存します。これで、非決定性が導入されました。

マルチスレッド アプリケーションで作業を割り当てるために使用されるプログラミング パターンの 1 つに、スレッド プールがあります。プール内のワーカー スレッドが実行するためにキューに入れられた作業項目が RNG を必要とし、実行ごとに実行を決定論的にしたい場合は、新しい作業項目をプールからプルした後、各スレッドで RNG を再シードする必要があります。列

  • これは、作業項目の初期化の一部として実行できます
  • シードには、ジョブのパラメーターのハッシュ関数が含まれる場合があります
  • これがどのようにコーディングされているかに注意すれば、ワーカー スレッドの数やキューからジョブを引き出す順序に関係なく、疑似ランダム性と決定性を実現できます。

これを扱うSOの質問は次のとおりです。インスタンスに関連付けられた決定論的乱数ジェネレーター(スレッドに依存しない)

シングル スレッド アプリケーションでは、RNG を再シードする必要はありません。実際、再シードすることによって、繰り返しが開始される前にサイクルが短くなるため、望ましくありません。これに対する例外は、@MatthewSanders が指摘した暗号化です。その場合、乱数が秘密鍵として使用されるため、最大のエントロピー (最小の決定論) が必要です。

于 2013-03-03T08:00:24.087 に答える