C++11のランダムライブラリを使った乱数の生成
タイトルの通り、新しいC++11の<random>
ライブラリを使って、乱数を生成する方法を考えています。以下のコードで試してみました。
std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);
このコードの問題点は、コンパイルして実行するたびに、いつも同じ数字が生成されてしまうことです。そこで質問ですが、ランダムライブラリの他の関数で、真にランダムでありながらこれを達成できるものはありますか?
私の特定の使用例では、[1, 10]
の範囲内の値を得ようとしていました。
127
3
MicrosoftのStephan T. Lavavej氏(stl)がGoing Nativeで、新しいC++11のランダム関数の使い方と、
rand()
を使わない理由について講演しました。その中で、あなたの疑問を基本的に解決するスライドが含まれていました。以下にそのスライドからコードをコピーしました。彼の講演の全文はこちらからご覧いただけます: http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful
これは、私がちょうどそのような内容で書いたものです。
~
よくある2つの状況があります。1つ目は、乱数が欲しくて、品質や実行速度にはあまりこだわらない場合です。その場合は、以下のマクロを使います。
を使用すると、0 から 1 - epsilon の範囲の p が得られます (RAND_MAX が double の精度より大きい場合は別ですが、それについては後で考えてください)。
int x = (int) (uniform() * N);
これで、0からN -1までのランダムな整数が得られます。
他の分布が必要な場合は、pを変換しなければなりません。また、uniform()を何度も呼び出す方が簡単な場合もあります。
繰り返し動作させたい場合は、定数でシードし、そうでなければtime()の呼び出しでシードします。
品質や実行時のパフォーマンスを気にするのであれば、uniform()を書き換えましょう。しかし、それ以外の場合はコードに触れないでください。uniform()は常に0から1マイナスεにしておきましょう。C++乱数ライブラリをラッピングしてよりよいuniform()を作ることもできますが、それは中レベルのオプションのようなものです。RNGの特性にこだわるのであれば、少し時間をかけて基本的な手法がどのように動作するかを理解し、それを提供することも価値があります。そうすれば、コードを完全にコントロールすることができ、プラットフォームやリンクしているC++のバージョンに関わらず、同じシードであれば、常に全く同じシーケンスになることが保証されます。