多くの疑似乱数ジェネレーターは、順番に「ウォームアップ」するために多くのサンプルを必要とすると読んだことがあります。std::random_device を使用して std::mt19937 をシードする場合、これは当てはまりますか、それとも構築後に準備が整うと期待できますか? 問題のコード:
#include <random>
std::random_device rd;
std::mt19937 gen(rd());
ベストアンサー1
Mersenne Twister はシフト レジスタ ベースの pRNG (疑似乱数ジェネレータ) であるため、0 または 1 が長く続く不良シードの影響を受けやすく、内部状態が十分に混乱するまでは比較的予測可能な結果になります。
ただし、単一の値を取るコンストラクタは、そのような「悪い」状態が生成される可能性を最小限に抑えるように設計された、そのシード値に対して複雑な関数を使用します。SeedSequencemt19937
コンセプトに準拠したオブジェクトを介して内部状態を直接設定する 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);