HOWTO · C++

C++ で 0 と 1 の間の乱数を生成する方法

この記事では、0 から 1 までの間隔の乱数を作成する方法を示します。

このページの内容

0以上1未満の浮動小数点擬似乱数を生成するには、C++11の乱数エンジンと std::uniform_real_distribution<double> を組み合わせます。この例では固定シードを使うため、同じ実装で同じエンジンとシードを使えば、同じ系列を再現できます。新しいC++コードでは <random> を使い、古いコードの保守では std::rand を使います。

C++11の<random>を使って浮動小数点数を生成する

<random>をインクルードして乱数エンジンを作成し、値が必要なときにそのエンジンを分布に渡します。エンジンは擬似乱数ビットの系列を生成し、分布はそのビットを指定した型と範囲の値に変換します。この一通り揃った例では、5つの値を出力します。固定シードを使うため、同じ標準ライブラリ実装では再実行しても同じ結果を再現できます。

#include <iostream>
#include <random>

int main() {
    std::mt19937 engine(2026);
    std::uniform_real_distribution<double> distribution(0.0, 1.0);

    for (int i = 0; i < 5; ++i) {
        std::cout << distribution(engine) << '\n';
    }
}

出力される数字は標準ライブラリの実装によって異なります。同じ実装で同じエンジンとシードを使うと、同じ系列が始まります。別の系列を使うには、異なるシードを指定するか、std::random_device から一度だけシードを取得してエンジンを初期化します。ただし、すべてのシステムでこのデバイスが非決定的なエントロピーを提供するとは限りません。

出力範囲を理解し、乱数エンジンを選ぶ

std::uniform_real_distribution<double>(0.0, 1.0) が指定する区間は半開区間です。0は返される可能性がありますが、1は含まれません。テンプレート引数で浮動小数点数の結果型(float、double、long double)を選びます。分布にはエンジンを渡す必要があり、分布だけでは乱数を生成できません。

エンジンが擬似乱数の系列を決め、シードがその系列の開始位置を決めます。std::mt19937 は、アルゴリズムが規定された広く使われている標準エンジンです。特定のエンジンを気にしない場合は std::default_random_engine が便利ですが、どのエンジンが選ばれるかは実装によって決まるため、異なる標準ライブラリ間で同じ系列が必要な場合には適しません。エンジンには一度だけシードを設定して使い続けてください。値を生成するたびに再シードすると、値が繰り返され、系列の質が損なわれることがあります。これらの機能はシミュレーション、ゲーム、一般的なランダム処理に適していますが、暗号用の秘密情報には適していません。

std::randはレガシーコードでのみ使う

古いコードでは、<cstdlib>で宣言される std::rand が使われていることがあります。これは0から RAND_MAX までの整数を返し、RAND_MAX も範囲に含まれます。整数同士の除算を避けるため、割る前に浮動小数点数へ変換します。たとえば、インライン式 static_cast<double>(std::rand()) / (static_cast<double>(RAND_MAX) + 1.0) は、整数を目的の範囲にスケーリングします。

このスケーリングでは、std::rand が RAND_MAX を返した場合も含め、結果は1未満に保たれます。実行ごとに異なる値を得るには、値の生成を始める前に std::srand を一度呼び出します。時間に基づくシードを使うこともよくありますが、実行を繰り返しても同じシードが使われる場合があります。また、シードを設定しても生成器の品質は向上しません。RAND_MAX は実装によって異なり、エンジンや系列を制御する機能も <random> より限られています。新しいコードではC++11のエンジンと分布を優先し、既存のインターフェイスで必要な場合に限って旧来の関数を使ってください。