C ++ 11での乱数生成:生成方法、その仕組み [閉まっている]


102

私は最近C ++ 11で乱数を生成する新しい方法に出くわしましたが、それについて読んだ論文を要約することができませんでした(「エンジン」、「分布」のような数学用語、「生成されたすべての整数が等しく可能性がある」)。

だから誰でも説明できますか

  • 彼らは何ですか?
  • 彼らはどういう意味ですか?
  • 生成する方法?
  • 彼らはどのように機能しますか?

乱数生成に関する1つのFAQですべてを呼び出すことができます。


6
分布が何であるかを知らずにRNGについて質問することは、式が何であるかを知らずに式パーサーについて尋ねるようなものです... C ++ 11のRNGライブラリは、統計を知っていて、rand、いくつかの基本的な統計とRNGの概念については、ウィキペディアをざっと見ておく必要があります。そうしないと<random>、さまざまな要素の根拠と使用法を説明するのが非常に難しくなります。
Matteo Italia

26
@マッテオ:ほとんど。子供は、分布が何であるかを理解していなくても、ダイが乱数を生成するという概念を理解できます。
ベンジャミンリンドリー2011

3
@ベンジャミン:それが彼の理解が止まるところです。それはまさに最初のステップ(エンジン)であり、なぜ彼らがフラットな分布を生成することが重要であるのかさえ理解していません。ライブラリの残りの部分はすべて、分布やその他の統計概念を理解せずに謎のままです。
Matteo Italia

回答:


142

質問は広範すぎて完全な答えにはなりませんが、いくつか興味深い点をまとめておきます。

なぜ「同程度に」

等しい確率でそれぞれ0、1、...、10の数を生成する単純な乱数ジェネレーターがあるとします(これを従来のと考えてくださいrand())。ここで、0、1、2の範囲の乱数が必要であり、それぞれの確率が同じです。あなたのひざけりの反応は取るでしょうrand() % 3。ただし、残りの0と1は残りの2よりも頻繁に発生するため、これは正しくありません。

これが、適切な分布が必要な理由です。これはUniform[0,2]、例のように、一様なランダム整数のソースを受け取り、それらを目的の分布に変換します。これを良いライブラリに任せるのが一番です!

エンジン

したがって、すべてのランダム性の中心には、特定の間隔で均一に分散され、理想的には非常に長い周期を持つ一連の数値を生成する優れた疑似乱数ジェネレーターがあります。の標準的な実装rand()は、多くの場合最適ではないため、選択することをお勧めします。線形合同法とメルセンヌツイスターは2つの優れた選択肢です(LGも実際にはでよく使用されrand()ます)。繰り返しますが、ライブラリにそれを処理させるのは良いことです。

使い方

簡単:まず、エンジンを設定してシードします。シードは「乱数」のシーケンス全体を完全に決定するため、/dev/urandoma)毎回異なる(たとえばから取得した)シーケンスを使用し、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>従来よりも優先するもう1つの重要な理由rand()は、乱数生成をスレッドセーフにする方法が非常に明確で明白になったことです。各スレッドに独自のスレッドローカルエンジンを提供するか、スレッドローカルシードにシードするか、またはアクセスを同期します。エンジンオブジェクトに。

その他

  • 興味深い記事 codeguru上のTR1ランダムに。
  • ウィキペディアには良い要約があります(@Justinに感謝)。
  • 原則として、各エンジンはtypedef a result_typeである必要があります。これは、シードに使用する正しい整数型です。バグのある実装があったstd::mt19937ためuint32_t、x64でシードを強制的に実行せざるを得なかったと思います。最終的にはこれを修正しMyRNG::result_type seed_valて、エンジンを非常に簡単に交換できるようにする必要があります。

もう一度、ケレクは私が取り組んでいたものよりもはるかに良い答えでパンチに私を倒します。+1
ジャスティン

@ジャスティン:私はたくさんのことを逃したと確信しています、このトピックにさらに側面を追加してください!:-)
Kerrek SB、2011

13
「どういうわけか人口をstd::random_device/dev/urandom
増やす

2
例では、std::random_device見つけることができるここに
WKS

1
ウィキペディアの記事のコードにはバグがあります。randomとrandom2は同じです。コードスニペットのコメントから、作者が<random>の機能の使用方法を理解していないことは明らかです。
user515430 2014

3

乱数ジェネレーターは、数値を指定すると、新しい数値を与える方程式です。通常、最初の数値を提供するか、システム時間などから取得した数値を提供します。

新しい数値を要求するたびに、以前の数値を使用して方程式を実行します。

乱数ジェネレーターは、他の数値よりも頻繁に同じ数を生成する傾向がある場合、あまり良いとは見なされません。つまり、1から5までの乱数が必要で、このような数値の分布があったとします。

  • 1:1%
  • 2:80%
  • 3:5%
  • 4:5%
  • 5:9%

2は他のどの数字よりも頻繁に生成されるため、他の数字よりも生成される可能性が高くなります。すべての数値が同等である場合、毎回各数値を取得する可能性は20%です。言い換えると、2が優先されるため、上記の分布は非常に不均一です。すべての20%の分布は均等になります。

通常、真の乱数が必要な場合は、乱数ジェネレーターではなく、天気やその他の自然源などからデータを取得します。


8
ほとんどの乱数ジェネレーターは、良い均等分布を生成します。それらはランダムではありません。問題は、それらが計算されるため、シーケンス内で十分な数が与えられた次の数を推測できることです(これにより、真に乱数が必要なセキュリティに悪影響を及ぼします)。ゲームやものについては大丈夫です。
マーティンヨーク

5
OPがC ++の<random>ヘッダーで提供されている機能に関する特定の情報を要求していると確信しています。この答えは、C ++はもちろんのこと、プログラミングにも対応していません。
ベンジャミンリンドリー2011

1
@Martin:セキュリティは必ずしも真の乱数のソースを必要としません。カウンターモードのAES(一例として)は、確定的であるにもかかわらず、非常にうまく機能します。これには、キーに妥当な量のエントロピーが必要ですが、真のランダム性は必要ありません。
ジェリーコフィン

@ベンジャミンリンドリー:ネバーマインド。もう一度読んで、私が間違っていることに気づきました。
N_A 2011
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.