C++ 乱数機能

最終更新: 2024-10-30 00:23:14 +0800 +0800
原文は英語で書かれています。あなたはAI翻訳版を読んでいます。

C++ の乱数ライブラリは、決定論的な エンジン と 分布 を分離します。エンジンは 指定された出力範囲で一様分布する値の列を生成します。分布はエンジンの出力を消費し、 要求された統計分布へ写像します。状態を継続する必要がある場合は、両方のオブジェクトを 存続させます。

cpp
#include <random>

std::mt19937_64 engine{std::random_device{}()};
std::uniform_int_distribution<int> die{1, 6};

int roll = die(engine); // Both engine and distribution may advance state.

std::mt19937 と std::mt19937_64 は擬似乱数エンジンです。固定した初期状態から 再現可能な列を生成します。std::default_random_engine は実装定義のため、テスト、 ファイル、プロトコルで実装間の同じ列が必要な場合には適しません。

要件に応じてシードを設定する #

決定論的なテストでは、文書化された明示的なシードを使用します。生成データを再現する 必要がある場合は、テスト失敗時にシードを記録します。

cpp
std::mt19937 engine{0x5EEDu};

std::random_device は、実装に適切なソースがある場合に非決定的な乱数を提供する ことを意図していますが、実装が決定論的なフォールバックを提供することもあります。 entropy() の値は推定値であり、推定できない場合は 0 になることがあります。 したがって random_device は非暗号シミュレーションの最善努力によるシードソースには 適していますが、移植可能な暗号学的安全性の保証にはなりません。鍵、トークン、 salt、nonce には、オペレーティングシステムの暗号乱数 API または検証済みの暗号 ライブラリを使用します。

std::seed_seq は複数のソースワードをエンジン状態へ展開できます。独立したストリーム が必要な場合、長寿命の複数エンジンに同じ小さな整数をシードしないでください。代わり にストリーム割り当てポリシーを確立して文書化します。

分布は剰余バイアスなしで範囲内の値を生成する #

Use the distribution that expresses the desired result:

cpp
std::uniform_int_distribution<int> index{0, static_cast<int>(size - 1)};
std::bernoulli_distribution enabled{0.25};
std::normal_distribution<double> noise{0.0, 1.0};

uniform_int_distribution の境界は両端を含みます。動的な境界は構築またはパラメーター 化する前に検証します。a > b の範囲は分布の事前条件に違反します。エンジンの出力 範囲が n で割り切れない限り、範囲内の一様結果に engine() % n を使わないで ください。そうしないと、一部の剰余がより頻繁に現れます。標準分布は指定された分布 に必要な棄却または写像処理を実行します。

分布はエンジンと交換可能ではありません。分布は状態を保持できます。たとえば正規分布 の実装が生成値をキャッシュすることがあります。そのため、シミュレーションの再現性 要件に応じて分布状態を保持またはリセットします。

寿命、再現性、シリアライズ #

エンジンを値渡しすると、意図的に別の列状態が作成されます。ヘルパーが呼び出し側の 列を進める必要がある場合は、参照渡しします。

cpp
int roll_die(std::mt19937_64& engine) {
    static std::uniform_int_distribution<int> die{1, 6};
    return die(engine);
}

static 分布は、呼び出しが同期されている場合にだけ安全です。可変状態を持つ可能性が あります。シミュレーションごとにパラメーターまたは状態が異なる場合は、分布の所有権 を明示する方が適切です。

標準エンジンは状態の書式付きストリーム入出力をサポートし、同じ標準エンジン仕様内で チェックポイントを可能にします。シリアライズした状態とともに、エンジン型、シード ポリシー、分布パラメーターを保存します。シリアライズされた列は暗号秘密の保管場所 ではなく、選択したエンジンと実装環境の保証を超えるバージョン間再現性をプロジェクト が主張してはなりません。

並行性 #

エンジンと分布のオブジェクトは可変状態であり、同期せずに同時変更してはなりません。 ストリームが独立している場合は各スレッドに専用のエンジンと分布を与え、1 つの順序 付き列が必要な場合は共有ジェネレーターを mutex で保護します。スレッドローカル ジェネレーターには意図的なシードポリシーが必要です。同じシードをすべてのスレッドへ 単純にコピーすると、並列乱数ではなく相関した同一ストリームが生成されます。

コメント

GitHub で閲覧・コメントする(投稿にはログインが必要です)