私はc ++ 11ランダムライブラリについて少し混乱しています。
私が理解していること:2つの異なる概念が必要です。
私が理解していないのは、なぜこれを使用しないのかです。
std::random_device rd;
std::uniform_int_distribution<int> dist(1, 5);
// get random numbers with:
dist(rd);
私の知る限り、これはうまくいきます。
代わりに、これはほとんどの例/サイト/記事で私が見つけたものです:
std::random_device rd;
std::mt19937 e{rd()}; // or std::default_random_engine e{rd()};
std::uniform_int_distribution<int> dist{1, 5};
// get random numbers with:
dist(e);
私は特別な使用について話していません。暗号化、基本的な入門記事です。
私の疑いはstd::mt19937
(またはstd::default_random_engine
)はシードを受け入れます。デバッグセッション中に同じシードを指定すると、デバッグが容易になります。
また、次の理由だけではありません。
std::mt19937 e{std::random_device{}()};
また、次の理由だけではありません。
std::mt19937 e{std::random_device{}()};
これを1度だけ行う場合は問題ないかもしれませんが、何度も行う場合は、_std::random_device
_を追跡し、不必要に作成/破棄しないことをお勧めします。
Libc ++のソースコードを調べて_std::random_device
_の実装を確認すると、非常に簡単です。これはstd::fopen("/dev/urandom")
の薄いラッパーです。したがって、_std::random_device
_を作成するたびに、別のファイルシステムハンドルが取得され、関連するすべてのコストが支払われます。
Windowsでは、私が理解しているように、_std::random_device
_はMicrosoft暗号APIへの呼び出しを表すため、これを行うたびに暗号ライブラリインターフェイスを初期化して破棄します。
それはあなたのアプリケーションに依存しますが、一般的な目的のために、私はこのオーバーヘッドを常に無視できるとは考えません。時々そうですが、これは素晴らしいことです。
これはあなたの最初の質問に結びついていると思います:
代わりに、これはほとんどの例/サイト/記事で私が見つけたものです:
_ std::random_device rd;
std::mt19937 e{rd()}; // or std::default_random_engine e{rd()};
std::uniform_int_distribution<int> dist{1, 5};
_
少なくとも私はそれについて考えています:
_std::mt19937
_は非常にシンプルで信頼性の高いランダムジェネレーターです。それは自己完結型であり、OSやその他のものを呼び出さずに、完全にプロセス内に存在します。実装は標準で必須であり、少なくともブーストでは、元の_mt19937
_ペーパーから派生したすべての場所で同じコードを使用しました。このコードは非常に安定しており、クロスプラットフォームです。これを初期化したり、クエリを実行したりすると、コンパイルしたプラットフォームで同様のコードにコンパイルされ、同様のパフォーマンスが得られると確信できます。
対照的に_std::random_device
_はかなり不透明です。あなたはそれが何であるか、それが何をするのか、それがどれほど効率的であるかを正確に知りません。実際に取得できるかどうかさえわかりません。作成しようとすると例外がスローされる可能性があります。あなたはそれが種を必要としないことを知っています。通常、そこから大量のデータを引き出すことは想定されていません。シードを生成するために使用するだけです。時には、それは暗号化APIへの素敵なインターフェースとして機能しますが、実際にそれを行う必要はなく、悲しいことに、そうでない場合もあります。 UNIXでは_/dev/random
_に対応する場合があり、_/dev/urandom/
_に対応する場合があります。これは、一部のMSVC暗号API(ビジュアルスタジオ)に対応する場合と、固定定数(mingw)の場合があります。あなたがいくつかの電話のためにクロスコンパイルするならば、それが何をするか知っている人。 (そして、_/dev/random
_を取得した場合でも、パフォーマンスが低下する可能性があるという問題がありますconsistent-エントロピープールがなくなるまで、うまく機能しているように見える可能性があります。犬のように遅く走ります。)
私の考えでは、_std::random_device
_はtime(NULL)
を使用したシードの改良版のようです-time(NULL)
はかなりくだらないので、それは低いバーです考えられるすべてのものをシードします。私は通常、time(NULL)
を使用してシードを生成した場合に、その日に使用します。それ以外ではあまり役に立たないと思います。
この記事 から始めるのが良いでしょう。
いくつかのポイントを合成します。
この「デバイス」から数値を読み取るのはどれほどコストがかかりますか?不定です。たとえば、Linuxシステム上の/ dev/randomからの読み取りであり、エントロピーを待機するために長時間ブロックする可能性があります(それ自体がさまざまな理由で問題になります)。
私の個人的な経験のために、私はそのことを通知しましたstd::random_device
は通常、単純な疑似ランダムアルゴリズムよりも低速です。それは一般的には真実ではないかもしれませんが、通常はそうです。これは、物理デバイス、または単純なCPU以外のハードウェアが含まれる可能性があるためです。
C++ 11のstd :: random_deviceは非決定的である必要はありません!実装では、固定シードを使用した単純なRNGとして実装できるため、プログラムの実行ごとに同じ出力が生成されます。