<random>
ヘッダは、擬似乱数を取り扱うための乱数生成器 (Random Number Generator) や分布生成器 (Distribution) 、非決定論的な乱数生成器、および関連する一連のクラス・関数を定義する乱数ライブラリである。
このヘッダでは、以下の標準ヘッダをインクルードする:
コンセプト
名前 | 説明 | 対応バージョン |
---|---|---|
uniform_random_bit_generator |
離散一様分布に従う乱数生成器(concept) | C++20 |
擬似乱数生成器
擬似乱数生成器は、ソフトウェアで乱雑な値のシーケンスを生成するクラスである。
擬似乱数生成器は、環境によらず同じシードを与えれば同じ乱数列が生成される。
多くのユーザーにとっては、以下に挙げる生の乱数生成器テンプレートクラスそのものよりも、後述するパラメータ定義済みの乱数生成器の型を使用すれば十分である。
名前 | 説明 | 対応バージョン |
---|---|---|
linear_congruential_engine |
線形合同法(class template) | C++11 |
mersenne_twister_engine |
メルセンヌツイスター法(class template) | C++11 |
subtract_with_carry_engine |
キャリー付き減算法(class template) | C++11 |
生成器アダプタ
生成器アダプタは、他の乱数生成器の乱数列を調整するクラスである。
通常、ユーザーがこれらのクラスを直接使用することはない。新たな乱数アルゴリズムを作る上級者、および研究者向けの機能である。
名前 | 説明 | 対応バージョン |
---|---|---|
discard_block_engine |
部分的に乱数列を破棄する(class template) | C++11 |
independent_bits_engine |
乱数生成器が生成するビットを変更する(class template) | C++11 |
shuffle_order_engine |
乱数の生成順をシャッフルする(class template) | C++11 |
パラメータ定義済み擬似乱数生成器
先に挙げた擬似乱数生成器に対して一般的なパラメータを定義し、使いやすいように用意された擬似乱数生成器の型。
これらの型には、パフォーマンス、オブジェクトのサイズ、周期などのトレードオフがある。ユーザーの目的に合わせて擬似乱数生成器の型を選択してほしい。
オブジェクトのサイズをある程度無視・許容できる状況では、多くの分野と用途に、mt19937
を推奨できる。
名前 | 説明 | 対応バージョン |
---|---|---|
minstd_rand0 |
最小標準MINSTD(type-alias) | C++11 |
minstd_rand |
最小標準MINSTDのパラメータ改良版(type-alias) | C++11 |
mt19937 |
メルセンヌツイスターの32ビット版(type-alias) | C++11 |
mt19937_64 |
メルセンヌツイスターの64ビット版(type-alias) | C++11 |
ranlux24_base |
RANLUX法のranlux24 を定義するための型(type-alias) |
C++11 |
ranlux48_base |
RANLUX法のranlux48 を定義するための型(type-alias) |
C++11 |
ranlux24 |
RANLUX法のレベル3(type-alias) | C++11 |
ranlux48 |
RANLUX法のレベル4(type-alias) | C++11 |
knuth_b |
KnuthのリオーダーアルゴリズムB(type-alias) | C++11 |
default_random_engine |
非専門用途でデフォルト使用する擬似乱数生成器(type-alias) | C++11 |
非決定論的な乱数生成器
擬似乱数には「予測できる」「再現性がある」という特徴がある。
暗号化、パスワードの生成、擬似乱数のシードを決定するといった、エンドユーザーに予測されたくない乱数列が必要な場合に、擬似乱数の代わりに、以下の非決定論的な乱数生成器を利用できる。
名前 | 説明 | 対応バージョン |
---|---|---|
random_device |
予測不能な乱数生成器(class) | C++11 |
シード数列
名前 | 説明 | 対応バージョン |
---|---|---|
seed_seq |
擬似乱数エンジンの為のシード数列(class) | C++11 |
分布生成器
分布生成器は、乱数生成器によって生成される値の範囲や分布を調整するクラスである。
分布生成器は、環境によって異なるアルゴリズムで実装される可能性がある。擬似乱数生成器は環境によらず同じシードを与えれば同じ乱数列が生成されるが、分布生成器を介して乱数生成する場合、環境によって異なる乱数列が生成される場合がある。
一様分布
名前 | 説明 | 対応バージョン |
---|---|---|
uniform_int_distribution |
一様整数分布(class template) | C++11 |
uniform_real_distribution |
一様実数分布(class template) | C++11 |
ベルヌーイ分布(Bernoulli Distribution)
名前 | 説明 | 対応バージョン |
---|---|---|
bernoulli_distribution |
ベルヌーイ分布(class) | C++11 |
binomial_distribution |
二項分布(class template) | C++11 |
geometric_distribution |
幾何分布(class template) | C++11 |
negative_binomial_distribution |
負の二項分布(class template) | C++11 |
ポワソン分布(Poisson Distribution)
名前 | 説明 | 対応バージョン |
---|---|---|
poisson_distribution |
ポワソン分布(class template) | C++11 |
exponential_distribution |
指数分布(class template) | C++11 |
gamma_distribution |
ガンマ分布(class template) | C++11 |
weibull_distribution |
ワイブル分布(class template) | C++11 |
extreme_value_distribution |
極値分布(class template) | C++11 |
正規分布(Normal Distribution)
名前 | 説明 | 対応バージョン |
---|---|---|
normal_distribution |
正規分布(class template) | C++11 |
lognormal_distribution |
対数正規分布(class template) | C++11 |
chi_squared_distribution |
カイ二乗分布(class template) | C++11 |
cauchy_distribution |
コーシー分布(class template) | C++11 |
fisher_f_distribution |
フィッシャーのF分布(class template) | C++11 |
student_t_distribution |
ステューデントのt分布(class template) | C++11 |
標本分布(Sampling Distribution)
名前 | 説明 | 対応バージョン |
---|---|---|
discrete_distribution |
整数のインデックスごとに離散した確率分布生成器(class template) | C++11 |
piecewise_constant_distribution |
区間ごとの重み付けを定数値とした分布生成器(class template) | C++11 |
piecewise_linear_distribution |
区間ごとの重み付けを線形に接続した分布生成器(class template) | C++11 |
ユーティリティ
名前 | 説明 | 対応バージョン |
---|---|---|
generate_canonical |
実数区間[0.0,1.0)に展開(事実上正規化)された一様分布乱数を得る(function template) | C++11 |
generate_random |
乱数列を生成する(function template) | C++26 |
例
以下に示す例では、標準の乱数ライブラリを用いてランダムデバイスでシードを生成してメルセンヌツイスタエンジンを初期化、単精度浮動小数点数型で区間[-1.0f, 1.0f)の一様分布、および1.0f
を中心として標準偏差0.5f
の正規分布に基づく擬似乱数を100万個生成し"random.tsv"にタブ区切り形式のファイルとして結果を保存する。
#include <fstream>
#include <random>
int main()
{
// メルセンヌ・ツイスター法による擬似乱数生成器を、
// ハードウェア乱数をシードにして初期化
std::random_device seed_gen;
std::mt19937 engine(seed_gen());
// 一様実数分布
// [-1.0f, 1.0f)の値の範囲で、等確率に実数を生成する
std::uniform_real_distribution<float> dist1(-1.0f, 1.0f);
// 正規分布
// 平均1.0f、標準偏差0.5fで分布させる
std::normal_distribution<float> dist2(1.0f, 0.5f);
std::ofstream file("random.tsv");
for (size_t i = 0; i < 1000*1000; ++i) {
// 各分布法に基いて乱数を生成
float r1 = dist1(engine);
float r2 = dist2(engine);
file << r1 << "\t" << r2 << "\n";
}
}
この例である時得られた random.tsv (ファイルサイズが大きいので添付する上では random.tsv.xz に圧縮) を元に、得られたデータの密度を図示すると、以下のような図が得られた。
破線は dist1 (一様分布; min=-1.0f, max=1.0f) 、実線は dist2 (正規分布; mean=1.0f, stdev=0.5f) 、横軸は値、縦軸は密度(値の件数を区間ごとに数えたヒストグラムを全体に占める割合で表したもの)である。
標準乱数ライブラリの基本的な使い方
「擬似」乱数生成器
擬似乱数生成器は決定論的で、再現性を持つ。
擬似乱数生成器に同じシードを与えることで、同じ乱数列を再現させられる。この挙動は開発中のテストやデバッグなどで有用である。
実行ごとに異なる乱数列が必要な場合、random_device
クラスのような非決定論的に実装される乱数をシードとして使用するとよい。
また、擬似乱数生成器は高速かつ高効率に動作するよう設計されている。 しかしながら、これらが生成する乱数列は真の乱数ではなく、周期を持つ。
<random>
が提供する擬似乱数生成器は暗号論的に安全ではない。
一方 random_device
は非決定論的である(ただし実装は処理系定義なので詳細は項目を参照すること)が、
速度は擬似乱数生成器に比べ遅く、特にエントロピープールが枯渇すると著しく悪化する。
モンテカルロ法など多数の乱数が必要な場合は擬似乱数生成器の使用を推奨する。
推奨する擬似乱数エンジン
基本的には32ビット版メルセンヌ・ツイスターの実装であるmt19937
、もしくはその64ビット版の実装であるmt19937_64
のどちらかを使用することを推奨する。
非専門用途のためのdefault_random_engine
というエンジン型も定義されているが、この型は環境によって乱雑度が低く、周期も短い擬似乱数エンジンの別名として定義される場合がある。
mt19937
は、状態の大きさがsizeof(std::uint_fast32_t) * (624 + 1)
だけあり、少々サイズが大きいが、それを受け入れられる状況であれば、デフォルトでmt19937
を採用しよう。このエンジンでは、乱雑度や周期の長さが問題になることは少ない。
特定の範囲の整数や浮動小数点数が必要な場合
uniform_int_distribution
やuniform_real_distribution
のような、専門特化した分布クラスを使用する。
古典的な方法として、特定の範囲の整数を生成するために、剰余演算が使われていた。たとえば[0, 6)
の範囲のランダムな整数が必要な場合には、int x = random_value % 6;
のようにしていた。この方法では、modulo biasと呼ばれる値の偏り問題が発生する。この場合は、[0, 3]
の値が出力される確率が17%で、[4, 5]
の値が出力される可能性は16%となり、小さい値の方が確率が高くなる。これは、出力される可能のある乱数の最大値が、剰余する値で割り切れない場合に発生する偏りである。
専門特化した一様分布のクラスを使用することで、そのような偏りは起こらなくなる。
シード生成法
リリース版においては、実行ごとに擬似乱数のシードが異なることが求められる。
random_device
クラスが非決定論的に実装されている環境ではこれを使用するのが望ましい。
古典的な方法として、シードにはstd::time(NULL)
で取得した現在時間 (エポックからの経過秒) が使われてきた。
しかしながら、この方法ではアプリケーションの起動時間によってシードを調整され、乱数列を制御されてしまう。
これを防ぐには、非決定論的な random_device
や CPU の RDRAND
命令などを使用してシードを生成するのがよいだろう。
バージョン
言語
- C++11
参照
分布アルゴリズム
乱数ライブラリの使い方
乱数ライブラリが導入された経緯
- N0352 Proposal for Standardization of Random Number Generators in C++
- N1398 A Proposal to Add an Extensible Random Number Facility to the Standard Library
- N1452 A Proposal to Add an Extensible Random Number Facility to the Standard Library (Revision 2)
- N1588 On Random-Number Distributions for C++0x
- N1837 Library Extension Technical Report Issues List
- N1914 A Proposal to Add Random-Number Distributions to C++0x
- N1932 Random Number Generation in C++0X: A Comprehensive Proposal
- N1933 Improvements to TR1’s Facility for Random Number Generation
- N2032 Random Number Generation in C++0X: A Comprehensive Proposal, version 2
- N2033 Proposal to Consolidate the Subtract-with-Carry Engines
- N2079 Random Number Generation in C++0X: A Comprehensive Proposal, version 3
- N2111 Random Number Generation in C++0X: A Comprehensive Proposal, version 4
- N2423 Recommendations for Resolving Issues re [rand], Version 2
- N2424 Recommendations for Resolving the 2007-09-21 Issues re [rand]