C++11のランダムライブラリを使った乱数の生成

タイトルの通り、新しいC++11の<random>ライブラリを使って、乱数を生成する方法を考えています。以下のコードで試してみました。

std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);

このコードの問題点は、コンパイルして実行するたびに、いつも同じ数字が生成されてしまうことです。そこで質問ですが、ランダムライブラリの他の関数で、真にランダムでありながらこれを達成できるものはありますか?

私の特定の使用例では、[1, 10]の範囲内の値を得ようとしていました。

ソリューション

MicrosoftのStephan T. Lavavej氏(stl)がGoing Nativeで、新しいC++11のランダム関数の使い方と、rand()を使わない理由について講演しました。その中で、あなたの疑問を基本的に解決するスライドが含まれていました。以下にそのスライドからコードをコピーしました。

彼の講演の全文はこちらからご覧いただけます: http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful


#include 
#include 

int main() {
    std::random_device rd;
    std::mt19937 mt(rd());
    std::uniform_real_distribution dist(1.0, 10.0);

    for (int i=0; i
解説 (9)

これは、私がちょうどそのような内容で書いたものです。

#include 
#include 
#include 

using namespace std;

//==============================================================
// RANDOM BACKOFF TIME
//==============================================================
class backoff_time_t {
  public:
    random_device                      rd;
    mt19937                            mt;
    uniform_real_distribution  dist;

    backoff_time_t() : rd{}, mt{rd()}, dist{0.5, 1.5} {}

    double rand() {
      return dist(mt);
    }
};

thread_local backoff_time_t backoff_time;

int main(int argc, char** argv) {
   double x1 = backoff_time.rand();
   double x2 = backoff_time.rand();
   double x3 = backoff_time.rand();
   double x4 = backoff_time.rand();
   return 0;
}

~

解説 (0)

よくある2つの状況があります。1つ目は、乱数が欲しくて、品質や実行速度にはあまりこだわらない場合です。その場合は、以下のマクロを使います。

#define uniform() (rand()/(RAND_MAX + 1.0))

を使用すると、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++のバージョンに関わらず、同じシードであれば、常に全く同じシーケンスになることが保証されます。

解説 (2)