1. ホーム
  2. c++

[解決済み] C++11で乱数生成:生成方法、動作は?[クローズド]

2022-10-04 09:45:30

質問

最近、C++11 で乱数を生成する新しい方法に出会いましたが、その方法を消化することができませんでした。 論文 を消化することができませんでした (これは何でしょう? エンジン のような数学の用語は 分布 ここで、生成されるすべての整数は 等しく ")となります。

というわけで、どなたか説明してください。

  • は何ですか?
  • どのような意味があるのでしょうか?
  • どのように生成するのですか?
  • どのように動作するのでしょうか?
  • その他

乱数生成に関するFAQを一通り呼び出すことができます。

どのように解決するのですか?

この質問は広すぎて完全な回答にはなりませんが、興味深い点をいくつかピックアップしてみましょう。

なぜ "等しく可能性があるのでしょうか。

0, 1, ..., 10 の数字をそれぞれ等しい確率で発生させる簡単な乱数発生器があるとします (これを古典的な rand() ). 今、あなたは 0, 1, 2 の範囲の乱数を、それぞれ同じ確率で発生させたいとします。あなたの直感的な反応としては rand() % 3 . しかし、余りの 0 と 1 は余りの 2 よりも頻繁に発生するので、これは正しくありません!

というわけで、ちゃんとした 分布 のように,一様な乱数整数の元を取り,希望する分布に変換するものです. Uniform[0,2] のような分布に変換します。これは良いライブラリに任せるのが一番です!

エンジン

このように、すべてのランダム性の中心は、ある間隔に一様に分布し、理想的には非常に長い周期を持つ数列を生成する優れた擬似乱数生成器です。の標準的な実装は rand() の標準的な実装が最良であるとは限らないので、選択肢があるのは良いことです。線形合同とメルセンヌ・ツイスターが良い選択肢です(LG は実際にしばしば rand() でよく使われます)、これもライブラリに任せるのがいいでしょう。

どのように動作するか

簡単です。まず、エンジンをセットアップし、シードを設定します。シードは乱数のシーケンス全体を決定するため、a) 別のもの (例えば /dev/urandom から取得したもの) を毎回使用し、b) 一連のランダムな選択肢を再作成したい場合は、シードを保存します。

#include <random>

typedef std::mt19937 MyRNG;  // the Mersenne Twister with a popular choice of parameters
uint32_t seed_val;           // populate somehow

MyRNG rng;                   // e.g. keep one global instance (per thread)

void initialize()
{
  rng.seed(seed_val);
}

これでディストリビューションを作成することができます。

std::uniform_int_distribution<uint32_t> uint_dist;         // by default range [0, MAX]
std::uniform_int_distribution<uint32_t> uint_dist10(0,10); // range [0,10]
std::normal_distribution<double> normal_dist(mean, stddeviation);  // N(mean, stddeviation)

...そして、このエンジンを使って乱数を作りましょう!

while (true)
{
  std::cout << uint_dist(rng) << " "
            << uint_dist10(rng) << " "
            << normal_dist(rng) << std::endl;

}

並行処理

もう一つの重要な理由は <random> を好むもう一つの重要な理由は、従来の rand() は、乱数生成をスレッドセーフにする方法が非常に明確で明白であることです。各スレッドに独自のスレッド ローカルのエンジンを提供し、スレッド ローカルのシードを使用するか、またはエンジン オブジェクトへのアクセスを同期させます。

その他

  • 興味深い記事 をcodeguruのTR1ランダムで見ることができます。
  • ウィキペディア には良いまとめがあります (ありがとう、@Justin)。
  • 原則的に、各エンジンは result_type を型付けする必要があります。これは、シードに使用する正しい積分型です。以前、バグだらけの実装で、無理矢理シードを std::mt19937uint32_t に変更する必要がありますが、いずれは修正されて MyRNG::result_type seed_val というように、エンジンを非常に簡単に交換できるようにします。