最終更新日時:
が更新

履歴 編集

<random>

random(C++11)

<random>ヘッダは、擬似乱数を取り扱うための乱数生成器 (Random Number Generator) や分布生成器 (Distribution) 、非決定論的な乱数生成器、および関連する一連のクラス・関数を定義する乱数ライブラリである。

擬似乱数生成器

擬似乱数生成器は、ソフトウェアで乱雑な値のシーケンスを生成するクラスである。

多くのユーザーにとっては、以下に挙げる生の乱数生成器テンプレートクラスそのものよりも、後述するパラメータ定義済みの乱数生成器の型を使用すれば十分である。

名前 説明 対応バージョン
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

以下に示す例では、標準の乱数ライブラリを用いてランダムデバイスでシードを生成してメルセンヌツイスタエンジンを初期化、単精度浮動少数型で区間[-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.0, 1.0)の値の範囲で、等確率に実数を生成する
  std::uniform_real_distribution<> dist1(-1.0, 1.0);

  // 正規分布
  // 平均1.0、標準偏差0.5で分布させる
  std::normal_distribution<> dist2(1.0, 0.5);

  std::ofstream file("random.tsv");
  for (size_t i = 0; i < 1000*1000; ++i) {
    // 各分布法に基いて乱数を生成
    double r1 = dist1(engine);
    double 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_distributionuniform_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

参照

分布アルゴリズム

乱数ライブラリの使い方

乱数ライブラリが導入された経緯

編集者向けの参照