C++ 標準ライブラリ <random>

C++ 標準ライブラリの<random>ヘッダーファイルは、乱数を生成するためのツール群を提供し、単純な一様分布から複雑な離散分布までを網羅しており、乱数を必要とするアプリケーションに幅広い選択肢を提供します。これらのツールは、シミュレーション、ゲーム開発、暗号アルゴリズムなどの分野で非常に役立ちます。

<random>擬似乱数の生成をサポートするだけでなく、シード(種)の制御やさまざまな確率分布にも対応しており、開発者は特定のニーズに合った乱数列を柔軟に生成できます。

<random>ライブラリは以下の3つの主要コンポーネントで構成されています:

  1. 乱数エンジン:擬似乱数を生成する中核であり、生成プロセスの再現性とランダム性を制御します。
  2. 乱数分布:生成される値が従う確率分布のタイプを制御します。
  3. 乱数アダプター:エンジンの動作を調整できます。例:discard_blockなどのアダプターです。

C++ では、乱数生成器(Random Number Generator, RNG)は大きく2つのカテゴリに分類できます:

  • 擬似乱数生成器:決定論的アルゴリズムを使用して、ランダムに見える数列を生成します。これらの数列は理論上は予測可能ですが、通常はほとんどのアプリケーションにとって十分にランダムです。
  • 真の乱数生成器:熱雑音や放射性崩壊などの物理的プロセスに基づいて乱数を生成しますが、C++標準ライブラリはこのような生成器を直接提供していません。

よく使われる乱数エンジン

エンジン説明
std::default_random_engineデフォルトの乱数エンジンで、実装はコンパイラに依存します。
std::minstd_rand線形合同法エンジンで、一様な擬似乱数列を生成します。
std::mt19937メルセンヌ・ツイスタ法で、一般的な乱数生成に適しています。
std::mt19937_6464ビットのメルセンヌ・ツイスタ法です。
std::ranlux24_baseキャリー付き減算エンジンで、高品質な生成に使用されます。
std::knuth_bKnuthシャッフル乱数生成器です。

よく使われるエンジンとしては、std::mt19937生成速度が速く、生成品質が高いため、広く推奨される乱数生成エンジンです。生成器はまた、seed()メソッドでシードを指定でき、再現可能な擬似乱数列を簡単に生成できます。

乱数分布の種類

1. 一様分布

分布説明
std::uniform_int_distribution特定の整数範囲内で一様分布を生成します。
std::uniform_real_distribution特定の浮動小数点数範囲内で一様分布を生成します。
std::mt19937 gen(seed);
std::uniform_int_distribution<int> dist(1, 100); // 生成 1 到 100 间的整数
int random_int = dist(gen);

2. 正規分布

分布説明
std::normal_distribution標準正規分布であり、中心対称で、自然現象のシミュレーションによく使用されます。
std::lognormal_distribution対数正規分布です。
std::mt19937 gen(seed);
std::normal_distribution<> dist(0, 1); // 平均值为0,标准差为1
double random_normal = dist(gen);

3. 離散分布

分布説明
std::discrete_distribution生成される乱数は、特定の確率を持つ整数の集合です。
std::bernoulli_distributionベルヌーイ分布。以下のみを生成しますtrue 或 false。
std::binomial_distribution二項分布です。
std::mt19937 gen(seed);
std::discrete_distribution<int> dist({40, 10, 50}); // 概率为40%、10%、50%
int random_discrete = dist(gen);

構文

使用する<random>ライブラリの基本的な手順は次のとおりです:

  • ヘッダーファイルをインクルードする<random>。
  • 乱数生成器オブジェクトを作成します。
  • 分布クラスを使用して乱数を生成します。

例

基本的な乱数の生成

例

#include <iostream>
#include <random>

int main() {
    // 乱数デバイスを使用して乱数シードを作成
    std::random_device rd;
   
    // 乱数シードを使用してメルセンヌ・ツイスタ乱数生成器を初期化
    std::mt19937 generator(rd());

    // 乱数を1つ生成
    std::cout << "Random number: " << generator() << std::endl;

    return 0;
}

出力結果:

Random number: 3499211612

注意:プログラムを実行するたびに、生成される乱数は異なる場合があります。

一様分布を使用する

例

#include <iostream>
#include <random>

int main() {
    // 乱数生成器を作成
    std::mt19937 generator;

    // 範囲が1から10までの一様分布の乱数生成器を作成
    std::uniform_int_distribution<int> distribution(1, 10);

    // 乱数を5つ生成して表示
    for (int i = 0; i < 5; ++i) {
        std::cout << "Random number: " << distribution(generator) << std::endl;
    }

    return 0;
}

出力結果:

Random number: 7
Random number: 10
Random number: 6
Random number: 2
Random number: 4

プログラムを実行するたびに、出力される乱数列は異なる場合があります。

正規分布を使用する

例

#include <iostream>
#include <random>
#include <iomanip>

int main() {
    // 乱数生成器を作成
    std::mt19937 generator;

    // 平均0、標準偏差1の正規分布の乱数生成器を作成
    std::normal_distribution<double> distribution(0.0, 1.0);

    // 出力形式を設定し、小数第2位まで表示
    std::cout << std::fixed << std::setprecision(2);

    // 乱数を5つ生成して表示
    for (int i = 0; i < 5; ++i) {
        std::cout << "Random number: " << distribution(generator) << std::endl;
    }

    return 0;
}
Random number: -0.15
Random number: 0.13
Random number: -1.87
Random number: 0.46
Random number: -0.21

mt19937 エンジンを使用してさまざまな分布の乱数を生成する:

例

#include <iostream>
#include <random>

int main() {
    // 1. シードと乱数エンジンを設定
    std::random_device rd; // 乱数デバイスがシードを生成
    std::mt19937 gen(rd()); // メルセンヌ・ツイスタエンジン

    // 2. 一様分布の整数
    std::uniform_int_distribution<> dist_int(1, 100);
    std::cout << "Uniform integer: " << dist_int(gen) << std::endl;

    // 3. 一様分布の浮動小数点数
    std::uniform_real_distribution<> dist_real(0.0, 1.0);
    std::cout << "Uniform real: " << dist_real(gen) << std::endl;

    // 4. 正規分布
    std::normal_distribution<> dist_normal(0, 1);
    std::cout << "Normal: " << dist_normal(gen) << std::endl;

    // 5. 離散分布
    std::discrete_distribution<> dist_discrete({10, 20, 70});
    std::cout << "Discrete: " << dist_discrete(gen) << std::endl;

    return 0;
}

乱数アダプター

乱数アダプターは生成動作を調整でき、主に2種類のアダプターがあります:

  1. std::discard_block_engine:一定数の生成値を破棄し、指定された間隔の値のみを保持して、ランダム性を低減します。
  2. std::independent_bits_engine:指定されたビット数の乱数を生成し、バイナリデータを直接生成するのに便利です。

例

#include <iostream>
#include <random>

int main() {
    std::random_device rd;
    std::mt19937 gen(rd());
    std::discard_block_engine<std::mt19937, 3, 2> discard_engine(gen);
    std::cout << "Discard block random number: " << discard_engine() << std::endl;

    return 0;
}

一般的な使い方

  • シードを使用して再現可能な乱数列を生成する:同じシードを指定すると、実行するたびに同じ数列が生成されます。
  • さまざまな分布の乱数を生成する:アプリケーションのシナリオに合った分布関数を選択することで、実際の問題をより適切にシミュレートできます。
  • 生成器のパフォーマンスを調整する:異なる乱数エンジンを使用して、生成パフォーマンスと精度のバランスを取ります。
その他の拡張