次の方法で共有


<random>

乱数生成の機能を定義し、一様に分布した乱数を作成できるようにします。

#include <random>

まとめ

乱数ジェネレーターは、一連の疑似乱数値を生成するオブジェクトです。 Uniform Random Number Generator (URNG) は、指定した範囲内で一様に分布した値を生成するジェネレーターです。 URNG として機能するように設計されたテンプレート クラスは、特定の共通する特徴 (この記事の後の方で説明) がある場合、エンジン と呼ばれます。 URNG を分布の operator() に対する引数として渡して URNG と分布を組み合わせることで、その分布によって定義されている方法で分布した値を生成でき、また、通常はそのように使用されます。

次のリンクを使用すると、この記事の主なセクションに移動します。

  • コード例

  • 分類別一覧

  • エンジンと分布

  • 解説

簡単なヒント

次に、<random> を使用する場合に留意すべきヒントを示します。

  • ほとんどの場合、URNG は分布で成形される必要がある生のビットを生成します (主な例外は、std::shuffle() です。これは URNG を直接使用するためです)。

  • URNG や分布の実行は変更操作を意味するため、URNG または分布の単一のインスタンス化を同時に、安全に呼び出すことはできません。 詳細については、「C++ 標準ライブラリ内のスレッド セーフ」を参照してください。

  • 複数のエンジンの定義済み typedef が提供されています。エンジンを使用している場合、これは URNG を作成するためのお薦めの方法です。

  • 大部分のアプリケーションに対して最も役立つ組み合わせは、mt19937 エンジンと uniform_int_distribution の組み合わせです (この記事の後の方にあるコード例に示されています)。

<random> ヘッダーには選択できるオプションが多数あり、これらはいずれも以前の C ランタイム関数 rand() より適しています。 rand() の不具合やこれらの不具合に対する <random> の対応の詳細については、このビデオを参照してください。

次のコード例では、非確定的なシードを使用して作成されたジェネレーターを使用して 5 つの乱数を生成する方法を示します。

#include <random>
#include <iostream>

using namespace std;

int main()
{
    random_device rd;   // non-deterministic generator
    mt19937 gen(rd());  // to seed mersenne twister.
                        // replace the call to rd() with a
                        // constant value to get repeatable
                        // results.

    for (int i = 0; i < 5; ++i) {
        cout << gen() << " "; // print the raw output of the generator.
    }
    cout << endl;
}

Output:

  

これらは高品質の乱数であり、このプログラムを実行するたびに変化しますが、有効範囲内である必要はありません。 この範囲を制御するには、次のコードに示すように、一様分布を使用します。

#include <random>
#include <iostream>

using namespace std;

int main()
{
    random_device rd;   // non-deterministic generator
    mt19937 gen(rd());  // to seed mersenne twister.
    uniform_int_distribution<> dist(1,6); // distribute results between 1 and 6 inclusive.

    for (int i = 0; i < 5; ++i) {
        cout << dist(gen) << " "; // pass the generator to the distribution.
    }
    cout << endl;
}

Output:

  

次のコード例では、一様に分布した乱数のジェネレーターを使用してベクトルと配列の内容をシャッフルする、より実用的な一連のユース ケースを示します。

// cl.exe /EHsc /nologo /W4 /MTd
#include <algorithm>
#include <array>
#include <iostream>
#include <random>
#include <string>
#include <vector>
#include <functional> // ref()

using namespace std;

template <typename C> void print(const C& c) {
    for (const auto& e : c) {
        cout << e << " ";
    }

    cout << endl;
}

template <class URNG>
void test(URNG& urng) {

    // Uniform distribution used with a vector
    // Distribution is [-5, 5] inclusive
    uniform_int_distribution<int> dist(-5, 5);
    vector<int> v;

    for (int i = 0; i < 20; ++i) {
        v.push_back(dist(urng));
    }

    cout << "Randomized vector: ";
    print(v);

    // Shuffle an array 
    // (Notice that shuffle() takes a URNG, not a distribution)
    array<string, 26> arr = { { "H", "He", "Li", "Be", "B", "C", "N", "O", "F",
        "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc",
        "Ti", "V", "Cr", "Mn", "Fe" } };

    shuffle(arr.begin(), arr.end(), urng);

    cout << "Randomized array: ";
    print(arr);
    cout << "--" << endl;
}

int main()
{
    // First run: non-seedable, non-deterministic URNG random_device
    // Slower but crypto-secure and non-repeatable.
    random_device rd;
    cout << "Using random_device URNG:" << endl;
    test(rd);

    // Second run: simple integer seed, repeatable results
    cout << "Using constant-seed mersenne twister URNG:" << endl;
    mt19937 engine1(12345);
    test(engine1);

    // Third run: random_device as a seed, different each run
    // (Desirable for most purposes)
    cout << "Using non-deterministic-seed mersenne twister URNG:" << endl;
    mt19937 engine2(rd());
    test(engine2);

    // Fourth run: "warm-up" sequence as a seed, different each run
    // (Advanced uses, allows more than 32 bits of randomness)
    cout << "Using non-deterministic-seed \"warm-up\" sequence mersenne twister URNG:" << endl;
    array<unsigned int, mt19937::state_size> seed_data;
    generate_n(seed_data.begin(), seed_data.size(), ref(rd));
    seed_seq seq(begin(seed_data), end(seed_data));
    mt19937 engine3(seq);
    test(engine3);
}

出力例とコード例の解説

  

このコードは、テスト テンプレート関数を使用した 2 つの異なるランダム化 (整数のベクターのランダム化と、インデックス付きデータの配列のシャッフル) を示しています。 最初のテスト関数の呼び出しでは、暗号的に安全で非確定的な、シード設定不可および繰り返し不可の URNG random_device を使用しています。 2 回目のテスト実行では、確定的な 32 ビットの定数シードを指定し、mersenne_twister_engine を URNG として使用しています。これは、結果が繰り返し可能であることを意味します。 3 回目のテスト実行は、random_device からの 32 ビットの非確定的な結果を使用して mersenne_twister_engine にシードを設定しています。 4 回目のテスト実行では、random_device の結果で埋められたシード シーケンスを使用することで、3 回目のテスト実行を拡張しています。これによって、32 ビット以上の非確定的なランダム性が効果的に得られます (それでもまだ暗号的に安全ではありません)。 詳細については、この続きを参照してください。

[ページのトップへ]

分類別一覧

Uniform Random Number Generator

URNG は、次の特性においてよく説明されます。

  1. 周期の長さ: 生成された数のシーケンスを繰り返すために、どれだけの回数の反復処理を行うか。 長いほど良いです。

  2. パフォーマンス: どれだけ迅速に数を生成できるか、どれだけメモリを使用するか。 値が小さいほど良いです。

  3. 品質: 生成されたシーケンスがどれほど真の乱数に近いか。 このことは、通常、"ランダム性" と呼ばれます。

次の各セクションでは、 <random> ヘッダーで提供されている Uniform Random Number Generator (URNG) を示します。

[ページのトップへ]

非確定的なジェネレーター

random_device クラス

外部デバイスを使用して、非確定的で暗号的に安全なランダム シーケンスを生成します。 通常、エンジンにシードを設定するために使用されます。 パフォーマンスは低いですが、品質は非常に高いです。 詳細については、「解説」を参照してください。

[ページのトップへ]

エンジンの Typedef と定義済みのパラメーター

エンジンとエンジン アダプターのインスタンス化用。 詳細については、「エンジンと分布」を参照してください。

名前

説明

default_random_engine

既定のエンジンの型定義です。

typedef mt19937 default_random_engine;

knuth_b

クヌース エンジン。

typedef shuffle_order_engine<minstd_rand0, 256> knuth_b;

minstd_rand0

1988 年の最小標準エンジン (ルイス、グッドマン、ミラー、1969 年)。

typedef linear_congruential_engine<unsigned int, 16807, 0, 2147483647> minstd_rand0;

minstd_rand

minstd_rand0 の改良版最小標準エンジン (パーク、ミラー、ストックマイヤー、1993 年)。

typedef linear_congruential_engine<unsigned int, 48271, 0, 2147483647> minstd_rand;

mt19937

32 ビット メルセンヌ ツイスタ エンジン (松本、西村、1998年)。

typedef mersenne_twister_engine<unsigned int, 32, 624, 397, 
    31, 0x9908b0df, 
    11, 0xffffffff, 
    7, 0x9d2c5680, 
    15, 0xefc60000, 
    18, 1812433253> mt19937;

mt19937_64

64 ビット メルセンヌ ツイスタ エンジン (松本、西村、2000年)。

typedef mersenne_twister_engine<unsigned long long, 64, 312, 156, 
    31, 0xb5026f5aa96619e9ULL, 
    29, 0x5555555555555555ULL, 
    17, 0x71d67fffeda60000ULL, 
    37, 0xfff7eee000000000ULL, 
    43, 6364136223846793005ULL> mt19937_64;

ranlux24

24 ビット RANLUX 法エンジン (マーティン・ルッシャー、フレッド・ジェームズ、1994年)。

typedef discard_block_engine<ranlux24_base, 223, 23> ranlux24;

ranlux24_base

ranlux24 のベースとして使用されます。

typedef subtract_with_carry_engine<unsigned int, 24, 10, 24> ranlux24_base;

ranlux48

48 ビット RANLUX 法エンジン (マーティン・ルッシャー、フレッド・ジェームズ、1994年)。

typedef discard_block_engine<ranlux48_base, 389, 11> ranlux48;

ranlux48_base

ranlux48 のベースとして使用されます。

typedef subtract_with_carry_engine<unsigned long long, 48, 5, 12> ranlux48_base;

[ページのトップへ]

エンジン テンプレート

エンジン テンプレートは、スタンドアロンの URNG または エンジン アダプター に渡されるベース エンジンとして使用されます。 通常、これらは定義済みのエンジンの typedef でインスタンス化され、分布に渡されます。 詳細については、「エンジンと分布」を参照してください。

linear_congruential_engine クラス

線形合同法アルゴリズムでランダム シーケンスを生成します。 最も単純で、最も低品質です。

mersenne_twister_engine クラス

メルセンヌ ツイスタ アルゴリズムでランダム シーケンスを生成します。 最も複雑で、random_device クラスを除いて最も高品質です。 パフォーマンスは非常に高速です。

subtract_with_carry_engine クラス

キャリー付き減算アルゴリズムでランダム シーケンスを生成します。 linear_congruential_engine の改善版ですが、mersenne_twister_engine より品質もパフォーマンスもかなり低いです。

[ページのトップへ]

エンジン アダプター テンプレート

エンジン アダプターは他の (ベース) エンジンを適応させるテンプレートです。 通常、これらは定義済みのエンジンの typedef でインスタンス化され、分布に渡されます。 詳細については、「エンジンと分布」を参照してください。

discard_block_engine クラス

ベースとなるエンジンから返された値を破棄することによってランダム シーケンスを生成します。

independent_bits_engine クラス

ベースのエンジンから返された値のビットを再パックすることで、指定したビット数でランダム シーケンスを生成します。

shuffle_order_engine クラス

ベースのエンジンから返された値を並べ替えることで、ランダム シーケンスを生成します。

[セクションのトップへ]

[ページのトップへ]

乱数分布

次の各セクションに、<random> ヘッダーで提供されている分布を示します。 分布は後処理メカニズムであり、通常は入力として URNG 出力を使用し、定義された統計的確率密度関数によって出力を分布させます。 詳細については、「エンジンと分布」を参照してください。

[ページのトップへ]

一様分布

uniform_int_distribution クラス

閉区間 [a, b] (包含的-包含的) 内の範囲にわたる一様の整数値分布を作成します。

uniform_real_distribution クラス

区間 [a, b) (包含的-排他的) 内の範囲にわたる一様の実数 (浮動小数点) 値分布を作成します。

generate_canonical

[0, 1) (包含的-排他的) にわたる特定の精度の実数 (浮動小数点) 値の均等分布を作成します。

[セクションのトップへ]

ベルヌイ分布

bernoulli_distribution クラス

bool 値のベルヌイ分布を作成します。

binomial_distribution クラス

整数値の二項分布を作成します。

geometric_distribution クラス

整数値の幾何分布を作成します。

negative_binomial_distribution クラス

整数値の負の二項分布を作成します。

[セクションのトップへ]

正規分布

cauchy_distribution クラス

実数 (浮動小数点) 値のコーシー分布を作成します。

chi_squared_distribution クラス

実数 (浮動小数点) 値のカイ 2 乗分布を作成します。

fisher_f_distribution クラス

実数 (浮動小数点) 値のフィッシャー分布 (スネデカーのフィッシャー分布またはフィッシャー-スネデカー分布とも呼ばれる) を作成します。

lognormal_distribution クラス

実数 (浮動小数点) 値の対数正規分布を作成します。

normal_distribution クラス

実数 (浮動小数点) 値の正規 (ガウス) 分布を作成します。

student_t_distribution クラス

実数 (浮動小数点) 値のスチューデントの t 分布を作成します。

[セクションのトップへ]

ポワソン分布

exponential_distribution クラス

実数 (浮動小数点) 値の指数分布を作成します。

extreme_value_distribution クラス

実数 (浮動小数点) 値の極値分布を作成します。

gamma_distribution クラス

実数 (浮動小数点) 値のガンマ分布を作成します。

poisson_distribution クラス

整数値のポワソン分布を作成します。

weibull_distribution クラス

実数 (浮動小数点) 値のワイブル分布を作成します。

[セクションのトップへ]

標本分布

discrete_distribution クラス

整数の離散分布を作成します。

piecewise_constant_distribution クラス

実数 (浮動小数点) 値の区分定数分布を作成します。

piecewise_linear_distribution クラス

実数 (浮動小数点) 値の区分線形分布を作成します。

[セクションのトップへ]

[ページのトップへ]

ユーティリティ関数

このセクションでは、<random> ヘッダーで提供される一般的なユーティリティ関数を示します。

seed_seq Class

バイアスのかかっていないスクランブルされたシード シーケンスを生成します。 ランダムな変量ストリームのレプリケーションを避けるために使用されます。 エンジンから多数の URNG がインスタンス化される場合に役立ちます。

演算子

このセクションでは、<random> ヘッダーで提供される演算子を示します。

operator==

演算子の左側の URNG が右側のエンジンと等しいかどうかを調べます。

operator!=

演算子の左側の URNG が右側のエンジンと等しくないかどうかを調べます。

operator<<

ステータス情報をストリームに書き込みます。

operator>>

ステータス情報をストリームから抽出します。

[ページのトップへ]

エンジンと分布

<random> で定義されているこれらのテンプレート クラス カテゴリのそれぞれの詳細については、次の各セクションを参照してください。 これらのテンプレート クラス カテゴリではいずれも引数として型を受け取り、共有のテンプレート パラメーター名を使って、実引数の型として許可されている、次の型のプロパティを表します。

  • IntType は、short、int、long、long long、unsigned short、unsigned int、unsigned long、または unsigned long long を示します。

  • UIntType は、unsigned short、unsigned int、unsigned long、または unsigned long long を示します。

  • RealType は、float、double、または long double を示します。

エンジン

エンジンとエンジン アダプターは、作成されるジェネレーターをそのパラメーターでカスタマイズするテンプレートです。

エンジンの実体はクラスまたはテンプレート クラスであり、そのインスタンス (ジェネレーター) は、最小値と最大値の範囲内で一様に分布した乱数のソースとして機能します。 エンジン アダプターは、他の乱数エンジンが作成した値を受け取って、何らかのアルゴリズムをこれらの値に適用することで、さまざまなランダム性プロパティを持つ値のシーケンスを提供します。

すべてのエンジンとエンジン アダプターには、次のメンバーが存在します。

  • typedef numeric-type result_type: ジェネレーターの operator() から返される型です。 numeric-typeは、インスタンス化時にテンプレート パラメーターとして渡されます。

  • result_type operator() : min() と max() の範囲内で一様に分布した値を返します。

  • result_type min(): ジェネレーターの operator() から返される最小値を返します。 エンジン アダプターは、ベース エンジンの min() の結果を使用します。

  • result_type max(): ジェネレーターの operator() から返される最大値を返します。 result_type が整数 (整数値) 型である場合、max() は実際に返される可能性のある最大の値 (包含的) になります。result_type が浮動小数点 (実数値) 型である場合、max() は返される可能性のあるすべての値より大きい最小の値 (非包含的) になります。 エンジン アダプターは、ベース エンジンの max() の結果を使用します。

  • void seed(result_type s): シード値 s を使用してジェネレーターにシードを設定します。 エンジンの場合、シグネチャは void seed(result_type s = default_seed) で、既定のパラメーターがサポートされます (エンジン アダプターでは、別個の void seed() が定義されています。次のサブセクションを参照してください)。

  • template <class Seq> void seed(Seq& q): seed_seq Seq を使用して、ジェネレーターにシードを設定します。

  • 引数 result_type x を持つ明示的なコンストラクター。作成されるジェネレーターには、seed(x) を呼び出した場合と同じようにシード値が設定されます。

  • 引数 seed_seq& seq を持つ明示的なコンストラクター。作成されるジェネレーターには、seed(seq) を呼び出した場合と同じようにシード値が設定されます。

  • void discard(unsigned long long count): operator() を count 回効果的に呼び出し、それぞれの値を破棄します。

エンジン アダプターでは、さらに次のメンバーがサポートされます (Engine はエンジン アダプターの最初のテンプレート パラメーターで、ベース エンジンの型を指定します)。

  • ベース エンジンの既定のコンストラクターからの場合と同様にジェネレーターを初期化する既定のコンストラクター。

  • 引数 const Engine& eng を持つ明示的なコンストラクター。 これは、ベース エンジンを使用したコピーの構築をサポートするためのものです。

  • 引数 Engine&& eng を持つ明示的なコンストラクター。 これは、ベース エンジンを使用した移動の構築をサポートするためのものです。

  • ベース エンジンの既定のシード値でジェネレーターを初期化する void seed()。

  • ジェネレーターの構築に使用されたベース エンジンを返す const Engine& base() プロパティ関数。

すべてのエンジンで、後続の operator() への呼び出しで生成される値のシーケンスを決定する状態が保守されます。 同じ型のエンジンからインスタンス化された 2 つのジェネレーターの状態は、operator== および operator!= を使って比較できます。 2 つの状態を比較した結果、等しければ、それらからは同じ値のシーケンスが生成されます。 オブジェクトの状態は、そのジェネレーターの operator<< を使用することにより、符号なし 32 ビット値のシーケンスとしてストリームに保存できます。 保存することによって状態が変化することはありません。 保存された状態は、operator>> を使用すれば、同じ型のエンジンからインスタンス化されたジェネレーターに読み込むことができます。

[ページのトップへ]

分布

分布の実体は、クラスまたはテンプレート クラスであり、そのインスタンスは、エンジンから取得された一様分布の乱数ストリームを、特定の分布を持った乱数ストリームに変換します。 すべての分布には、次のメンバーが存在します。

  • typedef numeric-type result_type: 分布の operator() から返される型です。 numeric-typeは、インスタンス化時にテンプレート パラメーターとして渡されます。

  • template <class URNG> result_type operator()(URNG& gen): 一様に分布する乱数値のソースとして gen を使い、格納されている分布のパラメーターを使用して、分布の定義に従って分布した値を返します。

  • template <class URNG> result_type operator()(URNG& gen, param_type p): 一様に分布する乱数値のソースとして gen を使い、パラメーター構造体 p を使用して、分布の定義に従って分布した値を返します。

  • typedef unspecified-type param_type: オプションとして operator() に渡されるパラメーターのパッケージで、格納されているパラメーターの代わりに使用して戻り値を生成します。

  • const param& コンストラクター: 格納されているパラメーターを、その引数から初期化します。

  • param_type param() const: 格納されているパラメーターを取得します。

  • void param(const param_type&): 格納されているパラメーターを、その引数から設定します。

  • result_type min(): 分布の operator() から返される最小値を返します。

  • result_type max(): 分布の operator() から返される最大値を返します。 result_type が整数 (整数値) 型である場合、max() は実際に返される可能性のある最大の値 (包含的) になります。result_type が浮動小数点 (実数値) 型である場合、max() は返される可能性のあるすべての値より大きい最小の値 (非包含的) になります。

  • void reset(): 次回 operator() を呼び出したときに、その結果が、その前にエンジンから取得された値に左右されないようにするため、キャッシュされている値をすべて破棄します。

パラメーター構造体は、分布に必要なすべてのパラメーターを格納するオブジェクトです。 これには、次のメンバーが含まれます。

  • typedef distribution-type distribution_type: 分布の型です。

  • 分布のコンストラクターと同じパラメーター リストを受け取る 1 つ以上のコンストラクター。

  • 分布と同じパラメーター アクセス関数。

  • 等値比較演算子と非等値比較演算子。

詳細については、この下にある参照サブトピックを参照してください (この記事で既にリンクされています)。

[ページのトップへ]

解説

次の比較表に示すように、Visual Studio には 2 つの非常に有用な URNG (mt19937 と random_device) があります。

URNG

高速か

暗号的に安全か

シード設定可能か

確定的か

mt19937

はい

はい

○*

random_device

はい

* 既知のシードが提供される場合。

ISO C++ 標準では random_device が暗号的に安全であることは要求されていませんが、Visual Studio では暗号的に安全であるように実装されています ("暗号的に安全" という用語は保証を示すものではありません。特定のランダム化アルゴリズムが提供する最小限のレベルのエントロピ (それによる予測可能性レベル) を意味しています。 詳細については、Wikipedia の記事「暗号論的擬似乱数生成器」を参照してください)。ISO C++ 標準ではこのことを要求していないため、他のプラットフォームでは (暗号的に安全でない) 簡単な疑似乱数ジェネレーターとして random_device が実装され、別のジェネレーターのシード ソースとしてのみ適する場合もあります。 クロスプラットフォーム コードで random_device を使用する場合は、これらのプラットフォームのドキュメントを参照してください。

定義上、random_device の結果は再現可能でなく、また、副作用として、他の URNG よりも実行がかなり遅い場合があります。 暗号的に安全であることが要求されない大部分のアプリケーションでは mt19937 または類似のエンジンを使用しますが、コード例に示すように、random_device の呼び出しでシードを設定することもできます。

[ページのトップへ]

参照

その他の技術情報

C++ 標準ライブラリのヘッダー ファイル