実際に実際に使用する必要がある<random>の乱数エンジンはどれですか?std :: mt19937?


21

C ++ <random>機能を実用的なプログラムで使用するとします(「実用的」の定義については、ここでの制約はこの質問の一部です)。おおよそ次のようなコードがあります。

int main(int argc, char **argv) {
    int seed = get_user_provided_seed_value(argc, argv);
    if (seed == 0) seed = std::random_device()();
    ENGINE g(seed);  // TODO: proper seeding?
    go_on_and_use(g);
}

私の質問は、あなたどのタイプを使うべきですENGINEか?

  • 私はいつもstd::mt19937タイプするのが速くて名前認識があったのでいつも言っていました。しかし最近では、みんなが言っているように、メルセンヌツイスターは非常にヘビー級でキャッシュに不向きで、他の人が行うすべての統計的検定にさえ合格していません。

  • std::default_random_engineそれは明らかな「デフォルト」なので言いたいのですが。しかし、それはプラットフォームによって異なりあれば、私にはわからない、それは統計的にどんな良いことだかどうかはわかりません。

  • 最近は誰もが64ビットプラットフォームを使用std::mt19937_64しているので、少なくともover を使用する必要がありstd::mt19937ますか?

  • 私が言いたいpcg64xoroshiro128、彼らは尊敬と軽量に見えるので、彼らは内に存在しない<random>すべてで。

  • 私は約何も知らないminstd_randminstd_rand0ranlux24knuth_b確かに彼らは何のために良いことがあります- 、など?

明らかに、ここにはいくつかの競合する制約があります。

  • エンジンの強さ。(<random>暗号的に強力なPRNGはありませんが、一部の標準化されたものは他のものよりも「弱い」ですよね?)

  • sizeof そのエンジン。

  • その速度operator()

  • 播種のしやすさ。mt19937初期化する状態が非常に多いため、適切にシードするのが難しいことで有名です。

  • ライブラリベンダー間の移植性。あるベンダーfoo_engineが別のベンダーとは異なる数値を生成する場合foo_engine、それは一部のアプリケーションには適していません。(うまくいけば、これは多分それ以外を除外しませんdefault_random_engine。)

これらすべての制約をできる限り考慮して、究極の「標準ライブラリ内にとどまるベストプラクティス」の答えは何でしょうか。を使い続けるべきstd::mt19937ですか、それとも何ですか?


2
最後に、すべての標準エンジンアダプターは、デフォルトで構築されたものの特定の連続した呼び出しで特定の値を返すように指定されているため、移植可能でなければなりません。
1201ProgramAlarm

回答:


15

C ++リファレンスには、C ++によって現在提供されているランダムエンジンがすべてリストされています。ただし、エンジンの選択には多くの課題があります(たとえば、高品質のランダムジェネレーターのリストを参照してください)。例えば:

  • default_random_engine は実装によって定義されるため、アプリケーションに問題がある可能性のある統計上の欠陥がエンジンにあるかどうかは不明です。
  • linear_congruential_engine線形合同ジェネレーターを実装します。ただし、モジュラスが素数で非常に大きい(少なくとも64ビット)場合を除いて、品質は低くなる傾向があります。また、彼らはそれらのモジュラスよりも多くのシードを受け入れることができません。
  • minstd_rand0minstd_rand約2 ^ 31の種子のみを認めます。knuth_ba minstd_rand0をラップし、それをBays–Durhamでシャッフルします。
  • mt19937また、mt19937_64初期化が適切であれば(たとえば、1つのstd::seed_seq出力random_deviceだけでなく、複数の出力を使用して初期化することにより)、より多くのシードを受け入れることができますが、約2500バイトの状態を使用します。
  • ranlux24そしてranlux48状態の577ビット約使用彼らは(彼らはいくつかを維持し、他の擬似ランダム出力を廃棄することによって動作する)遅いです。

ただし、C ++には、別のエンジンをラップして、ランダム性のプロパティを潜在的に改善する2つのエンジンもあります。

  • discard_block_engine 指定されたランダムエンジンの出力の一部を破棄します。
  • shuffle_order_engine 特定のランダムエンジンのベイズダーラムシャッフルを実装します。

例えば、それはのベイ・ダーラムのシャッフル持っている、と言う、可能ですmt19937ranlux24またはカスタムlinear_congruential_engineとをshuffle_order_engine。おそらく、ラップされたエンジンは元のエンジンよりも高品質です。ただし、新しいエンジンの統計的品質をテストせずに予測することは困難です。

したがって、そのようなテストが保留中の場合、それはmt19937今のところC ++標準で最も実用的なエンジンのようです。ただし、C ++の将来のバージョンに別の乱数エンジンを追加する提案が少なくとも1つあることは承知しています(C ++ペーパーP2075を参照)。


1

よるC ++リファレンスdefault_random_engine

ライブラリの実装が、比較的カジュアルな、専門家でない、および/または軽量な使用のために少なくとも許容可能なエンジン動作を提供するジェネレータ選択したかどうか。

したがって、軽量で使用する場合は、何も心配する必要はありません。シードdefault_random_engine使用すれば、それでEpoch Time (time(0))十分です;)


ここでの問題は移植性だと思います。デフォルトは適切に機能するエンジンである場合がありますが、別のプラットフォームでは再現できない場合があります。
bremen_matt

@bremen_mattうーん...まあ、なぜ「ランダムな」数を再現する必要があるのですか?
Farbod Ahmadian

2
テスト。テストの目的で、再現可能な入力が必要です。同時に、これらの入力をランダムにする必要がある場合があります。たとえば、ほとんどの機械学習アルゴリズムは、パラメータがランダムに初期化されることを前提としています。Ransac、CNN、DNNなど...多くのアルゴリズムでは、ランダムなパラメーターが必要です。
bremen_matt
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.