Manakah dari mesin angka acak <random> yang harus digunakan dalam praktik? std :: mt19937?

21

Misalkan Anda ingin menggunakan <random>fasilitas C ++ dalam program praktis (untuk beberapa definisi "praktis" - kendala di sini adalah bagian dari pertanyaan ini). Anda memiliki kode yang kira-kira seperti ini:

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);
}

Pertanyaan saya adalah, untuk tipe apa Anda harus menggunakannya ENGINE?

  • Saya dulu selalu mengatakan std::mt19937karena itu cepat untuk mengetik dan memiliki pengenalan nama. Tapi hari ini sepertinya semua orang mengatakan bahwa Mersenne Twister sangat berat dan tidak bersahabat dan bahkan tidak lulus semua tes statistik yang dilakukan orang lain.

  • Saya ingin mengatakan std::default_random_enginekarena ini adalah "standar" yang jelas. Tetapi saya tidak tahu apakah itu bervariasi dari satu platform ke platform lainnya, dan saya tidak tahu apakah ini baik secara statistik.

  • Karena semua orang ada di platform 64-bit hari ini, haruskah kita setidaknya menggunakan std::mt19937_64lebih std::mt19937?

  • Saya ingin mengatakan pcg64atau xoroshiro128karena mereka tampaknya dihormati dan ringan, tetapi mereka tidak ada <random>sama sekali.

  • Aku tidak tahu apa-apa tentang minstd_rand, minstd_rand0, ranlux24, knuth_b, dll - pasti mereka harus baik untuk sesuatu?

Jelas ada beberapa kendala yang bersaing di sini.

  • Kekuatan mesin. ( <random>tidak memiliki PRNG yang kuat secara kriptografis, tetapi masih, beberapa yang terstandarisasi "lebih lemah" daripada yang lain, kan?)

  • sizeof mesin.

  • Kecepatannya operator().

  • Kemudahan penyemaian. mt19937sangat sulit untuk diunggulkan dengan benar karena memiliki begitu banyak kondisi untuk diinisialisasi.

  • Portabilitas antara vendor perpustakaan. Jika satu vendor foo_enginemenghasilkan angka yang berbeda dari vendor lain foo_engine, itu tidak baik untuk beberapa aplikasi. (Semoga ini tidak mengesampingkan apa pun kecuali mungkin default_random_engine.)

Menimbang semua kendala ini sebaik mungkin, apa yang akan Anda katakan adalah jawaban "praktik terbaik yang ada di perpustakaan"? Haruskah saya terus menggunakan std::mt19937, atau apa?

Quuxplusone
sumber
2
Ke poin terakhir Anda, semua adaptor mesin standar ditentukan untuk mengembalikan nilai tertentu pada permintaan khusus berturut-turut dari default yang dibuat, sehingga harus portabel.
1201ProgramAlarm

Jawaban:

15

Referensi C ++ daftar semua mesin acak yang saat ini disediakan oleh C ++. Namun, pemilihan mesin meninggalkan banyak hal yang diinginkan (misalnya, lihat daftar saya generator acak berkualitas tinggi ). Contohnya:

  • default_random_engine didefinisikan-implementasi, jadi tidak diketahui apakah mesin memiliki kelemahan statistik yang mungkin diperhatikan oleh aplikasi.
  • linear_congruential_enginemengimplementasikan generator linier kongruensial. Namun, mereka cenderung memiliki kualitas yang buruk kecuali modulusnya prima dan sangat besar (setidaknya 64 bit). Juga, mereka tidak bisa menerima lebih banyak biji daripada modulus mereka.
  • minstd_rand0dan minstd_randhanya mengakui sekitar 2 ^ 31 biji. knuth_bmembungkus minstd_rand0dan melakukan shuffle Bays-Durham itu.
  • mt19937dan mt19937_64bisa menerima lebih banyak benih jika mereka diinisialisasi lebih baik (misalnya, dengan menginisialisasi std::seed_seqdengan beberapa output random_device, bukan hanya satu), tetapi mereka menggunakan sekitar 2500 byte negara.
  • ranlux24dan ranlux48menggunakan sekitar 577 bit state tetapi mereka lambat (mereka bekerja dengan menyimpan beberapa dan membuang output pseudorandom lainnya).

Namun, C ++ juga memiliki dua mesin yang membungkus mesin lain untuk berpotensi meningkatkan sifat keacakannya:

  • discard_block_engine membuang beberapa output dari mesin acak yang diberikan.
  • shuffle_order_engine mengimplementasikan pengocokan Bays – Durham dari mesin acak yang diberikan.

Sebagai contoh, mungkin, katakanlah, untuk memiliki shuffle Bays-Durham mt19937, ranlux24, atau kustom linear_congruential_enginedengan shuffle_order_engine. Mungkin mesin yang dibungkus lebih berkualitas daripada yang asli. Namun, sulit untuk memprediksi kualitas statistik mesin baru tanpa mengujinya .

Jadi, sambil menunggu tes seperti itu, tampaknya itu mt19937adalah mesin paling praktis dalam standar C ++ untuk saat ini. Saya menyadari, bagaimanapun, dari setidaknya satu proposal untuk menambahkan mesin angka acak lain untuk versi C ++ di masa depan (lihat kertas C ++ P2075 ).

Peter O.
sumber
1

Menurut C ++ Reference , default_random_engine:

Apakah pemilihan implementasi perpustakaan terhadap generator yang menyediakan setidaknya perilaku mesin yang dapat diterima untuk penggunaan yang relatif kasual, tidak ahli, dan / atau ringan.

Jadi untuk penggunaan ringan Anda tidak perlu khawatir tentang apa pun, benih default_random_enginedengan Epoch Time (time(0))dan itu akan cukup baik;)

Farbod Ahmadian
sumber
Saya percaya bahwa masalah di sini adalah portabilitas. Meskipun defaultnya adalah mesin yang berkinerja baik, itu mungkin tidak dapat direproduksi pada platform lain.
bremen_matt
@bremen_matt Hmm ... Nah, mengapa kita perlu mereproduksi nomor "acak"?
Farbod Ahmadian
2
Pengujian. Untuk tujuan pengujian, Anda membutuhkan input yang dapat direproduksi. Pada saat yang sama, Anda mungkin ingin atau membutuhkan input tersebut secara acak. Sebagai contoh, sebagian besar algoritma pembelajaran mesin mengasumsikan bahwa parameter diinisialisasi secara acak. Ransac, CNNs, DNNs, ... banyak algoritma memerlukan parameter acak.
bremen_matt