読者です 読者をやめる 読者になる 読者になる

kanetaiの二次記憶装置

プログラミングに関するやってみた、調べた系のものをQitaに移して、それ以外をはてブでやる運用にしようと思います。http://qiita.com/kanetai

rand, arc4random, random

C++での乱数の使い方をまとめとく。

rand, srand

Cの標準ライブラリを使う方法。srandでシードを設定して、randで
0以上, RAND_MAX以下の整数乱数を発生させる。
良くやるのは
time_t time(time_t *timer);
を使うやり方。引数のtimerには戻り値と同じ現在の暦時刻が代入される。
必要なけりゃぬるぽをいれときゃおk。

ただし、グローバル関数を使ってるので、プログラム全体で一つの乱数生成器しか利用できない。
シミュレーション用途だと、再現性を保証するための状態管理がむずかしくなる。
RAND_MAX: 2147483647 までの一様乱数しか生成できない。
乱数の質もあまり良くないらしい。
乱数の範囲は、剰余演算で制御できる。

srand(static_cast<unsigned>(time(nullptr))); //srand呼ばないと毎回同じ結果になる
std::cout << "max: " << RAND_MAX << std::endl;
REP(i, LOOP) std::cout << rand()%(MAX+1) << " ";
std::cout << std::endl;

arc4random

ANSI Cにはないので、使えない場合もある。
iOS/Macでは使えてます。に入っているみたい
randと違って、シードを設定する必要がない。

arc4random_stir 関数が、 /dev/urandom からデータを読み取り、
それを使用して Fn arc4random_addrandom によって S-Box の順序を変える。
なるほど、わからん。

とにかく、
arc4randomは自分自身で初期化するため、arc4random_stirを呼ぶ必要はない。
/dev/urandomからデータを読み取るって書いてあるから、boost::random_device()と同じようなもんなのかな?
非決定性、初期化の必要はない。

REP(i, LOOP) std::cout << arc4random()%(MAX+1) << " ";
std::cout << std::endl;

random

C++11だと使えるはずだけど、Boost Randomと少し違う点がある。
seedの設定にはseed_seqを使う。
seed_seqのコンストラクタは初期化用ベクタイテレータをとる。
初期化用のベクタの長さはいくらでもいいみたい。長くても、全要素が使われるとは限らない。
別にシードはseed_seqでなくてもいいみたいなので、std::random_deviceとかarc4random()とかtime(nullptr)とかでも良い気もする。

std::random_device rnd;
//std::mt19937_64 rnd;
    
std::vector< std::uint_least32_t > v(10); //初期用ベクタ
std::generate( v.begin(), v.end(), std::ref(rnd) ); //algorithm generateを使って、初期用ベクタを埋める
std::seed_seq seed(v.begin(), v.end());
std::mt19937 engine( seed );
//std::mt19937 engine(rnd());
std::uniform_real_distribution<> distribution(0, 1.0);
 
std::cout << "min: " << engine.min() << " max: " << engine.max() << std::endl;
REP(i,10) std::cout << engine() << std::endl;
std::cout << std::endl;
    
std::cout << "min: " << rnd.min() << " max: " << rnd.max() << std::endl;
REP(i,10) std::cout << distribution(engine) << std::endl;
std::cout << std::endl;

Boost.Randomとの大きな違いは、variate_generatorがないこと。
なので、こんな感じにbindを使って書いたりする。

auto myrnd = std::bind( std::uniform_real_distribution<double>(0.0, 1.0), std::mt19937(arc4random()) );
REP(i,10) std::cout << myrnd() << std::endl;