random
数日お泊りしてたので書けませんでした、傍から見るとまさに3日坊主。
twitterで某先輩が「srand/randを教えるぐらいならC++11のrandomを教えろ」と申されていたので、まとめてみる。
C++11でrandom
という標準ライブラリが追加された。
この中には様々な(疑似)乱数生成器、それらの分布を変更する分布生成器などが格納されている。
乱数生成器はtemplate classとして実装されているが、それらのパラメータを既に設定してある乱数生成器もtypedefで定義されている。
大抵の場合はこちらを使用すればことは足りるため、今回書いていくのも後者の設定済み生成器である。
とりあえず、それらの基本的なものをいくつか取り上げていく。
まずは非決定的な乱数の生成エンジン、random_device
。
int main() { // 返ってくる結果の最小値と最大値 cout << "min:" << random_device::min() << endl; cout << "max:" << random_device::max() << endl; // 適当に5回ほど乱数を出力 random_device rd; for(int i = 0; i < 5; ++i) { cout << rd() << endl; } }
非決定的な乱数というのは、つまり予測ができない乱数である。
ソフトウェアでは基本的に疑似乱数しか生成できないため、ハードウェアのノイズなどを用いて乱数を生成する。
これを使えばシード値に影響されない、本当の意味での乱数を生成できるが、欠点として速度が遅いことが挙げられる。
次にメルセンヌツイスタ、mt19937
及び64bit長のmt19937_64
。
int main() { // 返ってくる結果の最小値と最大値 cout << "min:" << mt19937::min() << endl; cout << "max:" << mt19937::max() << endl; // seedにrandom_deviceで生成した乱数を設定する random_device rd; mt19937 mt(rd()); // 適当に5回ほど乱数を出力 for(int i = 0; i < 5; ++i) { cout << mt() << endl; } }
vs2010ではminとmaxがstaticではなかったので注意、vs2012では動作確認済み。
メルセンヌツイスタの特徴は、高品質の乱数を高速に生成できるという点である。迷ったらこれ使っておけばいい。
コンストラクタでシード値が指定できるが、何も指定しなかった場合はデフォルト引数に5489u
が指定されている。
シード値はコンストラクタのほか、seed
メンバ関数でも変更することができる。
また、指定した回数だけ乱数を生成して破棄し、強制的に内部状態を進めるdiscard
というメンバ関数も持っている。
mt19937_64
も同様。
ほかにもrand
関数でお馴染みの線形合同法などもあるが、わざわざ使う理由も今のところないので省略する。
次は乱数を一様の確率で指定の範囲に分布させるuniform distribution
。
int main() { // seedにrandom_deviceで生成した乱数を設定する random_device rd; mt19937 mt(rd()); // 0以上10以下の間に一様分布させる乱数生成器 uniform_int_distribution<int> uid(0, 10); uniform_real_distribution<double> urd(0.0, 10.0); // それぞれ5回ずつ乱数を出力 for(int i = 0; i < 5; ++i) { cout << uid(mt) << endl; } for(int i = 0; i < 5; ++i) { cout << urd(mt) << endl; } }
uniform_int_distribution<char>
を指定すれば、文字のランダム生成もできる。
分布の範囲をあとから取得する場合はmin/max
あるいはa/b
がそれぞれに対応している。
分布のパラメータをあとから取得/設定する場合はparam
を使えばよい。
ほかにはnormal_distribution
で正規分布や、poisson_distribution
でポワソン分布など、様々な分布生成器が利用できる。
今日は眠いのでここら辺で。