C++0x時代の乱数

VC++2010の乱数を調べてみました。まだまだ実験中ですがorz

まずは生の乱数。

//線形合同法
std::minstd_rand mr( 12345u );
std::cout << "max : " << (mr.max)() << " min : " << (mr.min)() << std::endl;
for( int i = 0; i < 10; ++i ){
	std::cout << mr() << std::endl;
}
//メルセンヌ・ツイスター
std::mt19937 mt( 12345u );
std::cout << "max : " << (mt.max)() << " min : " << (mt.min)() << std::endl;
for( int i = 0; i < 10; ++i ){
	std::cout << mt() << std::endl;
}
//64bit版メルセンヌ・ツイスター
std::mt19937_64 mt64( 67890u );
std::cout << "max : " << (mt64.max)() << " min : " << (mt64.min)() << std::endl;
for( int i = 0; i < 10; ++i ){
	std::cout << mt64() << std::endl;
}
//真の乱数
std::random_device rd;
std::cout << "max : " << (rd.max)() << " min : " << (rd.min)() << std::endl;
for( int i = 0; i < 10; ++i ){
	std::cout << rd() << std::endl;
}

他にもいろいろありそうですが、とりあえず普通はメルセンヌ・ツイスタがあれば他を使うことはまずないかと。最後の真の乱数は文字通り、生成規則のない本当の乱数らしいです。どうやって生成しているんでしょうね?ハードウェアのノイズとか拾っているのかな?

実際に使う場合は乱数を生で使うことはまずないと思われます。大抵は何かしらの分布に変換すると思われます。

std::mt19937 mt( 12345u );
//整数の分布(min <= rand <= max)
std::uniform_int_distribution<> ui( 0, 10 );
for( int i = 0; i < 10; ++i ){
	std::cout << ui( mt ) << std::endl;
}
//浮動小数点の分布(半開区間)
std::uniform_real_distribution<> ur( 0.0, 1.0 );
for( int i = 0; i < 10; ++i ){
	std::cout << ur( mt ) << std::endl;
}
//正規分布(μ,σ)
std::normal_distribution<> nd( 10.0, 0.5 );
for( int i = 0; i < 10; ++i ){
	std::cout << nd( mt ) << std::endl;
}

他にもポアソン分布とかΧ二乗分布とかいろいろありそうです。使い方は実際に分布を得る際に生の乱数オブジェクトを引数に渡します。

で、一番困ったのがシャッフル。探したのだがどうやら新しく作られてないっぽい?既存のライブラリとしてrandom_shuffleがあるのでこれを根性で使うしかないのか?

std::vector< int > a;

auto rnd = [&](int i){ return std::uniform_int_distribution<>(0,i-1)(mt); };
std::random_shuffle( a.begin(), a.end(), rnd );

なんか汚いなぁ(´・ω・`)