はじめに
C言語由来の古い rand()
関数は、乱数の質が低く、現代のプログラミングでは推奨されません。C++11では、より高品質で柔軟な乱数生成のための <random>
ライブラリが導入されました。
<random>
ライブラリは、2つの要素から構成されます。
- エンジン (Engine): 擬似乱数の元となる整数列を生成します。(例:
std::mt19937
) - 分布 (Distribution): エンジンが生成した整数列を、特定の確率分布(一様分布、正規分布など)に従うように変換します。
この記事では、<random>
ライブラリの基本的な使い方を、3つの代表的な分布の例で解説します。
【前提】C++11とは?
C++11は、2011年に正式化されたC++言語のメジャーアップデート版です。<random>
ライブラリはこのC++11で導入されたため、利用するにはC++11以降に対応したコンパイラが必要です。
1. 一様分布の整数乱数を生成する
指定した範囲内の整数が、同じ確率で出現する、最も一般的な乱数です。「1から6までのサイコロの目」などがこれにあたります。
サンプルコード
#include <iostream>
#include <random> // <random>ライブラリ
using namespace std;
int main() {
// 1. 乱数のシードを準備
random_device seed_generator;
// 2. 乱数エンジンをシードで初期化 (メルセンヌ・ツイスター)
mt19937 random_engine(seed_generator());
// 3. 分布オブジェクトを作成 (1から100までの整数)
uniform_int_distribution<> distributor(1, 100);
cout << "1から100までの一様整数乱数を5個生成:" << endl;
for (int i = 0; i < 5; ++i) {
// 4. 分布オブジェクトにエンジンを渡して、乱数を生成
cout << distributor(random_engine) << endl;
}
return 0;
}
2. 正規分布(ガウス分布)の乱数を生成する
平均値を中心に、標準偏差に応じたばらつきを持つ乱数を生成します。自然現象のシミュレーションなどで使われます。
サンプルコード
#include <iostream>
#include <random>
using namespace std;
int main() {
random_device seed_generator;
mt19937 random_engine(seed_generator());
// 平均50.0, 標準偏差10.0の正規分布
normal_distribution<double> distributor(50.0, 10.0);
cout << "平均50, 標準偏差10の正規分布に従う乱数を5個生成:" << endl;
for (int i = 0; i < 5; ++i) {
cout << distributor(random_engine) << endl;
}
return 0;
}
3. 確率を指定して乱数を生成する(離散分布)
「1が出る確率が60%、2が30%、3が10%」のように、各整数値が出現する**重み(確率)**を個別に指定して乱数を生成します。
サンプルコード
#include <iostream>
#include <random>
#include <vector>
using namespace std;
int main() {
random_device seed_generator;
mt19937 random_engine(seed_generator());
// インデックス0, 1, 2, 3 が出現する重みを設定
vector<double> weights = {60.0, 20.0, 15.0, 5.0}; // 合計100でなくてもOK
discrete_distribution<size_t> distributor(weights.begin(), weights.end());
cout << "重み付けされた乱数を10個生成 (0-3):" << endl;
for (int i = 0; i < 10; ++i) {
// 0, 1, 2, 3 のいずれかのインデックスが、重みに応じて返される
cout << distributor(random_engine) << " ";
}
cout << endl;
return 0;
}
解説: discrete_distribution
は、weights
ベクターのインデックス(0, 1, 2, 3)を、対応する重みに比例した確率で返します。
まとめ
今回は、C++11の<random>
ライブラリを使った、高品質で多彩な乱数生成の方法を解説しました。
random_device
で予測不能なシードを生成する。mt19937
などの乱数エンジンをシードで初期化する。uniform_int_distribution
などの分布オブジェクトに必要なパラメータを設定する。分布(エンジン)
の形で呼び出して、目的の乱数を取得する。
この「エンジンと分布の分離」という設計により、C++の乱数ライブラリは非常に高い柔軟性と再利用性を実現しています。