乱数

現在トークンを任意の座標に配置するプログラムを生成しています
ふとランダムに配置する関数も評価用に必要かな?と思いましたので
標準ライブラリにある<random>を使ってみようと思います

乱数

rondom_deviceクラスの変数を宣言すると勝手に乱数が出来上がっているそうです

#include <random>

int main () 
{
  std::random_device rand;

  //operator()で乱数を出力
  std::cout << rand() << std::endl;
}

簡単でしたね しかし、このstd::random_deviceは予測不能乱数であるものの
実行速度が遅いようです
(ハードウェアの温度や時刻などから生成しているらしい)

したがって、このピュア乱数をseedとして、擬似乱数クラスを使用するほうが良い模様ですね

擬似乱数クラスはまず3種類あるみたいです

linear_congruential_engine   // 線形合同法(class template)
mersenne_twister_engine      // メルセンヌツイスター法(class template)
subtract_with_carry_engine   // キャリー付き減算法(class template)

これらは算出手法を提供しているだけみたいで
実際には以下のようなtypedefを利用すると良いようです

default_random_engine   // 非専門用途でデフォルト使用する擬似乱数生成器
minstd_rand0            // 線形合同法/最小標準MINSTD
minstd_rand             // 線形合同法/最小標準MINSTDのパラメータ改良版
mt19937                 // メルセンヌツイスターの32ビット版
mt19937_64              // メルセンヌツイスターの64ビット版

これら以外にもあるそうですが割愛します
今回はメルセンヌツイスタ法を使いたいと思います

void random_placement(int seed s)
{
  // 引数ctorでseedを受け取る
  std::mt19937 mt(s);
  
  for(auto& a : a){
    auto a = mt();
    //
    // いろいろ処理する
    //
  }
}

int main()
{
  std::random_device sd;
  random_placement(sd());
}

分布

有限範囲で乱数を使う場合は乱数(擬似乱数)をそのまま使用する
のではなく、分布関数を利用すると偏りがなくなって良いようです

こちらも使って見ましょう

一様分布、ベルヌーイ分布、ポワソン分布、正規分布、標本分布など
ありすぎて紹介できないので割愛します

今回は一様分布を遣って見ます

int main()
{
  std::random_device sd;
  std::mt19937 mt(sd());

  // 引数ctor(a,b)でa~bの範囲の一様分布生成器を作る
  std::uniform_int_distribution<> dist(0,10);

  // operator()(乱数)を呼び出す
 dist(mt);
}

http://melpon.org/wandbox/permlink/uGFJuYdqFDWud0hZ

ちなみに、以下の書き方がメジャーのようです

int main()
{
  std::random_device sd;

  // 引数ctor(a,b)でa~bの範囲の分布生成器を作る
  // std::bindでuniform_int_distribution関数の第1引数をstd::mt19937で束縛する
  auto dist = std::bind(std::uniform_int_distribution<>(0,10),std::mt19937(sd()))

  // operator()(乱数)を呼び出す
 dist();
}

参考:
http://en.cppreference.com/w/cpp/numeric/random
https://sites.google.com/site/cpprefjp/reference/random
http://siv3d.hateblo.jp/entry/2013/02/17/231829