多くの擬似乱数ジェネレーターは、「ウォームアップ」するために多くのサンプルを必要とすることを読みました。std::random_device を使用して std::mt19937 をシードする場合、または構築後に準備ができていると期待できますか? 問題のコード:
#include <random>
std::random_device rd;
std::mt19937 gen(rd());
多くの擬似乱数ジェネレーターは、「ウォームアップ」するために多くのサンプルを必要とすることを読みました。std::random_device を使用して std::mt19937 をシードする場合、または構築後に準備ができていると期待できますか? 問題のコード:
#include <random>
std::random_device rd;
std::mt19937 gen(rd());
Mersenne Twister はシフト レジスタ ベースの pRNG (疑似乱数ジェネレーター) であるため、内部状態が十分に混同されるまで、比較的予測可能な結果につながる 0 または 1 の長いランを伴う不良シードの影響を受けます。
ただし、単一の値を取るコンストラクターは、そのような「悪い」状態を生成する可能性を最小限に抑えるように設計されたシード値に対して複雑な関数を使用します。mt19937
SeedSequence コンセプトに準拠したオブジェクトを介して、内部状態を直接設定する場所を初期化する 2 つ目の方法があります。この 2 番目の初期化方法では、'良い' 状態の選択またはウォームアップの実行について考慮する必要がある場合があります。
この標準には、SeedSequence の概念に準拠した と呼ばれるオブジェクトが含まれていますseed_seq
。seed_seq
任意の数の入力シード値を取り、これらの値に対して特定の操作を実行して、pRNG の内部状態を直接設定するのに適した一連の異なる値を生成します。
std::mt19937
以下は、状態全体を満たすのに十分なランダム データでシード シーケンスをロードする例です。
std::array<int, 624> seed_data;
std::random_device r;
std::generate_n(seed_data.data(), seed_data.size(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
std::mt19937 eng(seq);
これにより、状態全体がランダム化されます。また、各エンジンは、seed_sequence から読み取るデータの量を指定しているため、ドキュメントを読んで、使用するエンジンの情報を見つけることができます。
ここでは、seed_seq を完全に から読み込みますがstd::random_device
、seed_seq
特にランダムではない数個だけがうまく機能するように指定されています。例えば:
std::seed_seq seq{1, 2, 3, 4, 5};
std::mt19937 eng(seq);
以下のコメントで、Cubbi はseed_seq
ウォームアップ シーケンスを実行することで機能することを示しています。
シードの「デフォルト」は次のとおりです。
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 rng(seed);
MTが「不十分に」シードされ、最適でないシーケンスが生じる状況があると思います. 私の記憶が正しければ、すべてゼロのシードはそのようなケースの 1 つです。これが深刻な問題である場合は、WELL ジェネレーターを使用することをお勧めします。私はそれらがより柔軟であると信じています-種子の品質はそれほど重要ではありません. (おそらく、あなたの質問にもっと直接的に答えてください。シードが不十分で、ジェネレーターを最適な状態にするためにサンプルの束を生成しようとするのではなく、シードを適切に行うことに集中する方がおそらく効率的です。)