C++の擬似乱数生成<random>


C++標準ライブラリには、ランダムと擬似乱数を生成するクラスが用意されています.次のようなクラスがあります.
  • 乱数生成クラス:乱数エンジン、乱数エンジンアダプタ、および事前定義乱数生成器を含む均一分布整数シーケンスを生成する擬似乱数生成器.
  • 乱数分布クラス:ジェネレータによって生成されたデジタルシーケンスを、均一分布、正規分布、ポアソン分布などの特定の乱数変数分布に従うデジタルシーケンスのオブジェクトに変換します.

  • 乱数エンジン
    乱数エンジンは、シードデータをエントロピーソースとして擬似乱数を生成することができる.
    ランダムシード:乱数ジェネレータを初期化し、アルゴリズムを使用して反復して乱数を生成します.最も簡単な使い方は、最初の乱数として次の乱数を生成することです.
    クラステンプレート
    さぎょう
    linear_congruential_engine
    線形同余アルゴリズムの実現
    mersenne_twister_engine
    メイソン巻き取りアルゴリズムの実現
    subtract_with_carry_engine
    帯域進位減少アルゴリズムの実現
    ここで、線形同余エンジンは一般的に速く、状態の記憶に対する要求は非常に小さい.遅延フィボナッチ生成器は,先進的な算術命令セットのないプロセッサでは非常に速いが,状態記憶が膨大で,あまり望ましくないスペクトル特性がある場合がある.メイソン巻き付け器は遅く、大きな状態記憶要件を有しているが、正しいパラメータがあれば、最も長い繰り返し不可能なシーケンスがあり、最も望ましいスペクトル特性を有する.
    ここでは,線形同余エンジンとメイソン巻き取り器の詳細な実装過程を紹介する.
    せんけいへいこうアルゴリズム
    線形同余アルゴリズムの実現は比較的簡単で、数学の表現は以下の通りである.
    X n + 1 = mod ( ( a ∗ X n + b ) , c ) X_{n+1} =\text{mod}\left(\left(a*X_n+b\right), c\right) Xn+1​=mod((a∗Xn​+b),c)
    しかし、そのパラメータa,b,cは一定の条件を満たす必要があり、ここでは、ネットワーク上のC++コードの実装を以下に示す.
    static uint32 prngState = 0;
    ​
    uint32 init_rand(uint32 seed)
    {
         
        //Seed the pseudo-random number generator
        prngState += seed;//Successful processing
        return SUCCESS;
    }
    ​
    uint32 _rand(void)
    {
         
        uint32 value;//Use a linear congruential generator (LCG) to update the state of the PRNG
        prngState *= 1103515245;
        prngState += 12345;
        value = (prngState >> 16) & 0x07FF;
    ​
        prngState *= 1103515245;
        prngState += 12345;
        value <<= 10;
        value |= (prngState >> 16) & 0x03FF;
    ​
        prngState *= 1103515245;
        prngState += 12345;
        value <<= 10;
        value |= (prngState >> 16) & 0x03FF;//Return the random value
        return value;
    }
    
    int32 rand_range(int32 min, int32 max)
    {
         
        int32 value;//Valid parameters?
        if (max > min)
        {
         
            //Pick up a random value in the given range
            value = min + (_rand() % (max - min + 1));
        }
        else
        {
         
            //Use default value
            value = min;
        }//Return the random value
        return value;
    }
    

    このコードは博文から抜粋したものである
    メイソン巻き
    メイソン巻き取り器の実現過程は複雑である
  • 第1段階:初期化され、ランダム種子に基づいて初期のメイソン回転鎖が得られる.
  • 第2段階:既存のメイソン回転チェーンに基づいて回転アルゴリズムを行い、次のサイクルの回転チェーンを取得する.
  • 第3段階:メイソン回転鎖に基づいて乱数を計算する.

  • そのC++コードは以下のように実現される.
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    bool isInit;
    int index;
    int MT[624];  //624 * 32 - 31 = 19937
    
    void srand(int seed)
    {
         
        index = 0;
        isInit = 1;
        MT[0] = seed;
        for(int i=1; i<624; i++)
        {
         
            int t = 1812433253 * (MT[i-1] ^ (MT[i-1] >> 30)) + i;
            MT[i] = t & 0xffffffff;   //    32 
        }
    }
    
    void generate()
    {
         
        for(int i=0; i<624; i++)
        {
         
            // 2^31 = 0x80000000
            // 2^31-1 = 0x7fffffff
            int y = (MT[i] & 0x80000000) + (MT[(i+1) % 624] & 0x7fffffff);
            MT[i] = MT[(i + 397) % 624] ^ (y >> 1);
            if (y & 1)
                MT[i] ^= 2567483615;
        }
    }
    int rand()
    {
         
        if(!isInit)
            srand((int)time(NULL));
        if(index == 0)
            generate();
        int y = MT[index];
        y = y ^ (y >> 11);
        y = y ^ ((y << 7) & 2636928640);
        y = y ^ ((y << 15) & 4022730752);
        y = y ^ (y >> 18);
        index = (index + 1) % 624;
    	return y;  //y         
    }
    
    int main()
    {
         
        srand(0);  //      
        int cnt = 0;
        for(int i=0; i<1000000; i++)  //                    
        {
         
            if(rand() & 1)
                cnt++;
        }
        cout<<cnt / 10000.0<<"%"<<endl;
        return 0;
    }
    

    このコードは私たちのネットワークから抜粋され、このブログには原理解析が含まれています.
    乱数エンジンアダプタ
    乱数エンジンアダプタは、別の乱数エンジンをエントロピー源とする擬似乱数を生成し、乱数エンジンに基づいてより多様性のあるランダムシーケンスを生成する.
    クラステンプレート
    さぎょう
    discard_block_engine
    乱数エンジンの出力の一部を破棄
    independent_bits_engine
    乱数エンジンの出力を指定したビット数のブロックにパッケージ化
    shuffle_order_engine
    乱数エンジンの出力を異なる順序で送信
    事前定義乱数ジェネレータ
    必要に応じて、上記の乱数エンジンと乱数エンジンアダプタに基づいて独自の乱数ジェネレータを構築できます.また、C++の標準ライブラリには、古典的な乱数ジェネレータが必要です.
    を選択します.
    定義#テイギ#
    minstd_rand0
    std::linear_congruential_engine<:uint_fast32_t>Lewis、GoodmanおよびMillerによって1969年に発見され、ParkおよびMillerによって1988年に「最小基準」として採択された.
    minstd_rand
    std::linear_congruential_engine<:uint_fast32_t>より新しい「最小基準」は、Park、MillerおよびStockmeyerに1993年に推奨された
    mt19937
     std::mersenne_twister_engine<:uint_fast32_t>                            0x9908b0df, 11,                                                         0xffffffff, 7,                                                         0x9d2c5680, 15,0 xefc 60000,18,1812433253>32ビットメイソン巻き付け器は、松本と西村によって1998年に設計された.
    mt19937_64
    std::mersenne_twister_engine<:uint_fast64_t>                            0xb5026f5aa96619e9, 29,                            0x5555555555555555, 17,                            0x71d67fffeda60000, 37,                            0xfff7eee000000000, 43,6364136223846793005>64ビットメイソン巻き取り器は、松本と西村が2000年に設計した
    ranlux24_base
    std::subtract_with_carry_engine<:uint_fast32_t/>
    ranlux48_base
    std::subtract_with_carry_engine<:uint_fast64_t/>
    ranlux24
    std::discard_block_engine<:ranlux24_Base>24ビットRANSUXジェネレータは、MartinLüscherとFred Jamesによって1994年に設計された
    ranlux48
    std::discard_block_engine<:ranlux48_ベース>48ビットRANSUXジェネレータは、MartinLüscherとFred Jamesによって1994年に設計された
    knuth_b
    std::shuffle_order_engine<:minstd_rand0/>
    default_random_engine
    インプリメンテーション定義
    らんすうぶんぷ
    乱数生成器の出力を処理して、出力結果が定義された統計確率密度関数に従って分布するようにする.
    きんいつぶんぷ
    uniform_int_distribution
    1つの範囲で均一に分布する整数値を生成する
    uniform_real_distribution
    1つの範囲で均一に分布する実数値を生成する
    ベルヌーイぶんぷ
    bernoulli_distribution
    バーヌリー分布上のbool値を生成
    binomial_distribution
    二項分布の整数値を生成
    negative_binomial_distribution
    負の二項分布の整数値を生成
    geometric_distribution
    幾何学的分布の整数値を生成
    ポアソンぶんぷ
    poisson_distribution
    ポアソン分布の整数値を生成
    exponential_distribution
    指数分布の実数値を生成
    gamma_distribution
    生成
    weibull_distribution
    ウィブール分布の実数値を生成
    extreme_value_distribution
    極値分布の実数値を生成
    せいじょうぶんぷ
    normal_distribution
    標準正規(Gauss)分布上の実数値を生成する
    lognormal_distribution
    対数正規分布の実数値を生成する
    chi_squared_义齿
    χ2
    cauchy_distribution
    コシ分布の実数値を生成
    fisher_f_distribution
    フィッシャーを生成
    student_t_distribution
    学生が生まれる
    サンプリングぶんぷ
    discrete_distribution
    離散分布上のランダム整数の生成
    piecewise_constant_distribution
    常子区間に分布する実数値を生成する
    piecewise_linear_distribution
    定義されたサブセクション間に分布する実数値を生成
    その他のツールstd::uniform_random_bit_generator:均一ランダムビットジェネレータは、符号なし整数値を返し、各値が可能な結果の範囲で(理想的に)等しい戻り確率を持つようにする関数オブジェクトである.std::random_device:ハードウェアエントロピーソースを用いた非確定乱数生成器std::generate_canonical:乱数生成器で得られたデータを[0,1]に均一に分布させるseed_seq:汎用的な偏差除去の混同シードシーケンスジェネレータは、シードの多様性を向上させることによってランダムシーケンスの重複出現を低減する