kanetaiの二次記憶装置

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

Boost.Random

Chapter 21. Boost.Random - 1.51.0

様々な分布の乱数の生成できる。
C言語標準のrand, srandはグローバル関数となっているが、
Boost Randomでは乱数計算はvariate_generatorオブジェクトでまとまっていている。
C+11で、randomが使えるようになったが、Boost Randomとは少し違う部分がある(variate_generatorがないとか)。

Boost Randomは大別すると、
variate_generator,
乱数生成エンジン、
分布、
randomm_number_generator
で形成されているみたい

名前空間/ヘッダ

boost

#include <boost/random.hpp>
#include <boost/nondet_random.hpp> //for random_device

乱数生成エンジン

ほとんどがテンプレートクラスだけど、通常typedefしたものを使えばいい。
毎回同じ値を出したければ、seedを指定せず、引数なしのコンストラクタを使えばいい。
生成乱数の最大値、最小値はメンバ関数min(), max()を使えば良い。

メモリ使用量は少ないが、遅め.
rand48は、64bit演算を利用して、周期を長くしている

    • minstd_rand0
    • minstd_rand
    • rand48
  • ecuyer1988

2種類の乱数生成エンジンの差をとる擬似乱数生成エンジン(seedは2つ)。

    • ecuyer1988
  • kreutzer1986

ベースの乱数生成エンジンの出力をランダムシャッフルして疑似乱数を生成するらしい

    • kreutzer19386
  • 逆数合同法

すごく...遅いらしいです...

    • hellekalek1995
  • Ranlux法

周期は 2^{500}だけど、あんま速くないみたいです。

    • ranlux64_3
    • ranlux64_4
  • Lagged Fibonacci法

速くて、周期が長いです(短いので 2^{32000}, 長いので 2^{2300000})。
そのかわりメモリ使用量は多いです。
BSD系のrandomで使われてる方法なんだって。

    • legged_fibonacci607
    • legged_fibonacci1279
    • legged_fibonacci2281
    • legged_fibonacci3217
    • legged_fibonacci4423
    • legged_fibonacci9689
    • legged_fibonacci19937
    • legged_fibonacci23209
    • legged_fibonacci44497
  • メルセンヌツイスター

周期ははそこそこ長く( 2^{11213}-1 or  2^{19337}-1)、高速。
メルセンヌツイスターってよく聞くけど、日本人が発明したのか...

    • mt11213b
    • mt19937
  • 非決定的乱数生成エンジン

boost/notdet_random.hppをインクルードする必要がある。
linux系だと"/dev/urandom"をみて、ハードウェア上のノイズなどから乱数生成してるらしい。
※libboost_random.aをリンクしとく

    • random_device

とりあえず、困ったらmt19937を使えば良さそう。
seedを入れたいときはrandom_deviceを使えばいいじゃないかな
めんどくさけりゃrandom_deviceだけでもいい気もする。

分布

  • 一様分布

min以上、max以下の数を当確率で発生させる.

uniform_smallint<class IntType = int>( IntType min = 0, IntType max = 9 )   //result_type = IntType
uniform_int<class IntType = int>( IntType min = 0, IntType max = 9 )        //result_type = IntType
uniform_real<class RealType = double>( RealType min = 0, RealType max = 1 ) //result_type = RealTypeType
  • ベルヌーイ分布

確率pでtrue, 確率(1-p)でfalseを発生させる

bernoulli_distribution<class RealType = double>( RealType p = 0.5) //result_type = bool
  • 二項分布

 0\leq x \leq tの整数xを確率 {}_t C_x p^x (1-x)^{t-x}で発生させる。

binomial_distribution<class IntType = int, class RealType = double>(IntType t = 1, RealType p = 0.5 ) //result_type = IntType
  • 幾何分布

確率 p^x(1-p)で整数xを発生させるらしい. 名前ぐらいしか聞いたことない.

geometric_distribution<class IntType = int, class RealType =double>(RealType p = 0.5) //result_type = IntType
  • 三角分布

最小値a, 中心値b, 最大値cの三角分布

triangle_distribution<class RealType = double>(RealType a = 0.0, RealType b = 0.5, RealType c = 1.0) //result_type = RealType
  • 指数分布

多分 f(x:\lambda) = \begin{cases} \lambda e - \lambda x & (x\geq 0) \\ 0 & (otherwise) \end{cases}

exponetial_distribution<class RealType = double>(RealType lamdba = 1.0) //result_type = RealType
  • ガンマ分布

ガンマ分布 - Wikipediaを読んだ。なるほど、わからん。

gamma_distribution<class RealType = double>(RealType alpha = 1) //result_type = RealType

 f(x) = \frac{\lambda ^x, e^{-\lambda}}{x!},  \lambda > 0
 E[ X] = V[ X] = \lambda
平均すなわち \lambdaを指定する。
二項分布で tp=\lambda, t\rightarrow \infty, p\rightarrow 0としたやつだっけ?

poisson_distribution<class IntType = int, class RealType = double>( RealType mean = 1 ) //result_type = IntType
normal_distribution<class RealType = double>(RealType mean = 0.0, RealType sigma = 1.0) // result_type = RealType
lognormal_distribution<class RealType = double>(RealType mean = 0.0, RealType sigma = 1.0) // result_type = RealType
  • コーシー分布

コーシー分布 - Wikipedia
 ´_ゝ`)フーン
中央値medianとスケールパラメータsigmaを指定するんだってさ。

cauchy_distribution<class RealType = double>(RealType median = 0, RealType sigma = 1) // result_type = RealType
  • 単位球面上一様分布

ちょっと他のと違って、dim次元の単位球面上に一様分布したdim次元のデータを返す。

uniform_on_sphere<class RealType = double, class Cont = std::vector<RealType> >(int dim = 2) //result_type = Cont

variate_generator

乱数生成エンジンと分布をあわせたクラス。
コンストラクタ

variate_generator(Engine e, Distribution d)

でエンジンと分布を設定して、operator()で乱数を生成する。
また、生成する値の最大値、最小値を求めるメンバ関数もある。

result_type variate_generator::min() const;
result_type variate_generator::max() const;
Boost Randomテスト

こんな感じで使う。

boost::random_device myseed;
//boost::mt19937 gen(static_cast<unsigned>(time(nullptr)));
boost::mt19937 gen(static_cast<unsigned>(myseed());
boost::triangle_distribution<> dst(MIN, MID, MAX);
boost::variate_generator<boost::mt19937, boost::triangle_distribution<> > r(gen, dst);
REP(i, LOOP) std::cout << r();
std::cout << std::endl
          << gen.min() << " " << gen.max() << std::endl
          << r.min()   << " " << r.max()   << std::endl;

乱数発生させて、gnuplotとかでヒストグラムや、散布図を書いてみると、ちゃんと指定した分布になって面白い。http://t16web.lanl.gov/Kawano/gnuplot/index.html
distribution

random_number_generator

指定したエンジンで、0以上、引数未満の整数をランダムに出力する関数オブジェクト。
呼び出すときに、上限値変更したいなら、boost::uniform_intで範囲制限するよりこっちの方が便利かもね。
別の用途として、std::random_shuffleの引数にも使える。

class Random{
public:
	Random(){ srand( static_cast<unsigned>( time(nullptr) ) ); }
	unsigned operator()(unsigned max){ return rand() % max; }
};

int main(){
    std::vector<int> v;
    REP(i, 10) v.push_back( i );
    std::vector<int> v2(v);

    //旧標準ライブラリだけでやる場合
    Random r;
    std::random_shuffle( v.begin(), v.end(), r );
    REP(i, 10) std::cout << v[i] << " ";
    std::cout << std::endl;
    
    //random_number_generatorを使う場合
    boost::random_device gen; //libboost_randomライブラリをリンクする必要あり
    std::random_shuffle( v2.begin(), v2.end(), boost::random_number_generator<boost::random_device>(gen) );
    REP(i, 10) std::cout << v2[i] << " ";
    std::cout << std::endl;
    
    boost::random_number_generator<boost::random_device> generator(gen);
    REP(i,10) std::cout << generator(101) << " ";
    std::cout << std::endl;
    return 0;
}