Seperti judulnya, saya mencoba mencari cara untuk menghasilkan angka acak menggunakan <random>
pustaka C ++ 11 yang baru . Saya sudah mencobanya dengan kode ini:
std::default_random_engine generator;
std::uniform_real_distribution<double> uniform_distance(1, 10.001);
Masalah dengan kode yang saya miliki adalah bahwa setiap kali saya mengkompilasi dan menjalankannya, selalu menghasilkan angka yang sama. Jadi pertanyaan saya adalah fungsi lain apa di pustaka acak yang dapat mencapai ini sementara benar-benar acak?
Untuk kasus penggunaan khusus saya, saya mencoba mendapatkan nilai dalam kisaran tersebut [1, 10]
std::mt19937
sebagai mesin kecuali Anda punya alasan kuat untuk tidak melakukannya. Dan distribusi adalah interval tertutup di kedua ujungnya.std::uniform_int_distribution
, yang adalah ditutup pada kedua ujungnya.Jawaban:
Stephan T. Lavavej (stl) dari Microsoft berbicara di Going Native tentang cara menggunakan fungsi acak C ++ 11 yang baru dan mengapa tidak menggunakannya
rand()
. Di dalamnya, ia menyertakan slide yang pada dasarnya menjawab pertanyaan Anda. Saya telah menyalin kode dari slide di bawah.Anda dapat melihat pembicaraan lengkapnya di sini: http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful
#include <random> #include <iostream> int main() { std::random_device rd; std::mt19937 mt(rd()); std::uniform_real_distribution<double> dist(1.0, 10.0); for (int i=0; i<16; ++i) std::cout << dist(mt) << "\n"; }
Kami menggunakan
random_device
sekali untuk menyemai generator nomor acak bernamamt
.random_device()
lebih lambat darimt19937
, tetapi tidak perlu di-seed karena meminta data acak dari sistem operasi Anda (yang akan bersumber dari berbagai lokasi, seperti RdRand misalnya).Melihat pertanyaan / jawaban ini , tampaknya
uniform_real_distribution
mengembalikan angka dalam rentang yang[a, b)
Anda inginkan[a, b]
. Untuk melakukan itu, kitauniform_real_distibution
seharusnya terlihat seperti:std::uniform_real_distribution<double> dist(1, std::nextafter(10, DBL_MAX));
sumber
default_random_engine
, menurut primer c ++ itu adalah salah satu yang dianggap paling berguna dalam penerapannyadefault_random_engine
ada.std::default_container
, semoga tidak ada orang menganggap diri mereka programmer yang tidak tahu perbedaannya, banyak bahasa skrip memiliki struktur tipe peta default, yang dapat diimplementasikan dalam berbagai cara yang mungkin tidak diketahui penggunanextafter
panggilan berlebihan untuk sebagian besar aplikasi. Kemungkinandouble
pendaratan acak tepat di titik akhir sangat kecil sehingga tidak ada perbedaan praktis antara memasukkan dan mengecualikannya.std::vector
analogi tidak bekerja di sini karenastd::vector
ini benar-benar default yang baik karena CPU caching. Bahkan mengunggulistd::list
untuk penyisipan di tengah. Itu benar bahkan jika Anda memahami semua container dan dapat membuat keputusan berdasarkan kerumitan algoritmik.Perpustakaan 'acak' saya menyediakan pembungkus nyaman yang tinggi di sekitar kelas acak C ++ 11. Anda dapat melakukan hampir semua hal dengan metode 'dapatkan' sederhana.
Contoh:
Nomor acak dalam suatu rentang
auto val = Random::get(-10, 10); // Integer auto val = Random::get(10.f, -10.f); // Float point
Boolean acak
auto val = Random::get<bool>( ) // 50% to generate true auto val = Random::get<bool>( 0.7 ) // 70% to generate true
Nilai acak dari std :: initilizer_list
auto val = Random::get( { 1, 3, 5, 7, 9 } ); // val = 1 or 3 or...
Iterator acak dari rentang iterator atau semua container
auto it = Random::get( vec.begin(), vec.end() ); // it = random iterator auto it = Random::get( vec ); // return random iterator
Dan bahkan lebih banyak hal! Lihat halaman github:
https://github.com/effolkronium/random
sumber
Saya merah semua hal di atas, sekitar 40 halaman lain dengan c ++ di dalamnya seperti ini dan menonton video dari Stephan T. Lavavej "STL" dan masih tidak yakin bagaimana angka acak bekerja dalam praksis jadi saya mengambil satu hari Minggu penuh untuk mencari tahu tentang apa itu semua dan bagaimana cara kerjanya dan dapat digunakan.
Menurut saya STL benar tentang "tidak menggunakan srand lagi" dan dia menjelaskannya dengan baik di video 2 . Dia juga merekomendasikan untuk menggunakan:
a)
void random_device_uniform()
- untuk generasi terenkripsi tetapi lebih lambat (dari contoh saya)b) contoh dengan
mt19937
- lebih cepat, kemampuan membuat benih, tidak terenkripsiSaya mengeluarkan semua buku yang diklaim c ++ 11 yang dapat saya akses dan menemukan bahwa Penulis Jerman seperti Breymann (2015) masih menggunakan tiruan dari
srand( time( 0 ) ); srand( static_cast<unsigned int>(time(nullptr))); or srand( static_cast<unsigned int>(time(NULL))); or
hanya dengan
<random>
alih - alih<time> and <cstdlib>
#includings - jadi berhati-hatilah untuk belajar hanya dari satu buku :).Artinya - itu tidak boleh digunakan sejak c ++ 11 karena:
Saya akhirnya menemukan penjelasan terbaik dari 20 buku di Bjarne Stroustrups yang lebih baru - dan dia seharusnya tahu barang-barangnya - di "A tour of C ++ 2019", "Programming Principles and Practice Using C ++ 2016" dan "The C ++ Programming Language 4th edition 2014 "dan juga beberapa contoh di" Lippmans C ++ primer 5th edition 2012 ":
Dan itu sangat sederhana karena generator bilangan acak terdiri dari dua bagian: (1) mesin yang menghasilkan urutan nilai acak atau pseudo-random. (2) distribusi yang memetakan nilai-nilai tersebut ke dalam distribusi matematika dalam suatu rentang.
Terlepas dari pendapat pria STL Microsoft, Bjarne Stroustrups menulis:
The
void die_roll()
Contoh adalah dari Bjarne Stroustrups - ide yang baik mesin pembangkit dan distribusi denganusing
(lebih pertarungan itu di sini) .Untuk dapat memanfaatkan secara praktis generator bilangan acak yang disediakan oleh pustaka standar di
<random>
sini beberapa kode yang dapat dieksekusi dengan contoh yang berbeda direduksi menjadi yang paling tidak diperlukan yang semoga aman waktu dan uang untuk kalian:#include <random> //random engine, random distribution #include <iostream> //cout #include <functional> //to use bind using namespace std; void space() //for visibility reasons if you execute the stuff { cout << "\n" << endl; for (int i = 0; i < 20; ++i) cout << "###"; cout << "\n" << endl; } void uniform_default() { // uniformly distributed from 0 to 6 inclusive uniform_int_distribution<size_t> u (0, 6); default_random_engine e; // generates unsigned random integers for (size_t i = 0; i < 10; ++i) // u uses e as a source of numbers // each call returns a uniformly distributed value in the specified range cout << u(e) << " "; } void random_device_uniform() { space(); cout << "random device & uniform_int_distribution" << endl; random_device engn; uniform_int_distribution<size_t> dist(1, 6); for (int i=0; i<10; ++i) cout << dist(engn) << ' '; } void die_roll() { space(); cout << "default_random_engine and Uniform_int_distribution" << endl; using my_engine = default_random_engine; using my_distribution = uniform_int_distribution<size_t>; my_engine rd {}; my_distribution one_to_six {1, 6}; auto die = bind(one_to_six,rd); // the default engine for (int i = 0; i<10; ++i) for (int i = 0; i <10; ++i) cout << die() << ' '; } void uniform_default_int() { space(); cout << "uniform default int" << endl; default_random_engine engn; uniform_int_distribution<size_t> dist(1, 6); for (int i = 0; i<10; ++i) cout << dist(engn) << ' '; } void mersenne_twister_engine_seed() { space(); cout << "mersenne twister engine with seed 1234" << endl; //mt19937 dist (1234); //for 32 bit systems mt19937_64 dist (1234); //for 64 bit systems for (int i = 0; i<10; ++i) cout << dist() << ' '; } void random_seed_mt19937_2() { space(); cout << "mersenne twister split up in two with seed 1234" << endl; mt19937 dist(1234); mt19937 engn(dist); for (int i = 0; i < 10; ++i) cout << dist() << ' '; cout << endl; for (int j = 0; j < 10; ++j) cout << engn() << ' '; } int main() { uniform_default(); random_device_uniform(); die_roll(); random_device_uniform(); mersenne_twister_engine_seed(); random_seed_mt19937_2(); return 0; }
Saya pikir itu menambahkan semuanya dan seperti yang saya katakan, saya butuh banyak membaca dan waktu untuk menjelaskannya pada contoh-contoh itu - jika Anda memiliki hal-hal lebih lanjut tentang pembuatan bilangan, saya senang mendengarnya melalui pm atau di bagian komentar dan akan menambahkannya jika perlu atau edit posting ini. Bool
sumber
Inilah sesuatu yang baru saja saya tulis di sepanjang baris itu:
#include <random> #include <chrono> #include <thread> using namespace std; //============================================================== // RANDOM BACKOFF TIME //============================================================== class backoff_time_t { public: random_device rd; mt19937 mt; uniform_real_distribution<double> dist; backoff_time_t() : rd{}, mt{rd()}, dist{0.5, 1.5} {} double rand() { return dist(mt); } }; thread_local backoff_time_t backoff_time; int main(int argc, char** argv) { double x1 = backoff_time.rand(); double x2 = backoff_time.rand(); double x3 = backoff_time.rand(); double x4 = backoff_time.rand(); return 0; }
~
sumber
Berikut adalah beberapa sumber daya yang dapat Anda baca tentang penghasil bilangan acak semu.
https://en.wikipedia.org/wiki/Pseudorandom_number_generator
Pada dasarnya, bilangan acak di komputer membutuhkan seed (nomor ini bisa menjadi waktu sistem saat ini).
Menggantikan
std::default_random_engine generator;
Oleh
std::default_random_engine generator(<some seed number>);
sumber
Anda punya dua situasi umum. Yang pertama adalah Anda menginginkan nomor acak dan tidak terlalu mempermasalahkan kualitas atau kecepatan eksekusi. Dalam kasus tersebut, gunakan makro berikut ini
#define uniform() (rand()/(RAND_MAX + 1.0))
yang memberi Anda p dalam kisaran 0 hingga 1 - epsilon (kecuali RAND_MAX lebih besar dari ketepatan ganda, tetapi khawatir tentang itu ketika Anda datang ke sana).
int x = (int) (seragam () * N);
Sekarang berikan bilangan bulat acak pada 0 sampai N -1.
Jika Anda membutuhkan distribusi lain, Anda harus mengubah p. Atau terkadang lebih mudah untuk memanggil uniform () beberapa kali.
Jika Anda ingin perilaku berulang, seed dengan konstanta, jika tidak seed dengan panggilan ke waktu ().
Sekarang jika Anda khawatir tentang kualitas atau kinerja waktu proses, tulis ulang uniform (). Namun sebaliknya jangan sentuh kode tersebut. Selalu pertahankan uniform () pada 0 hingga 1 dikurangi epsilon. Sekarang Anda bisa membungkus pustaka nomor acak C ++ untuk membuat uniform () yang lebih baik, tapi itu semacam opsi tingkat menengah. Jika Anda merasa terganggu dengan karakteristik RNG, ada baiknya juga menginvestasikan sedikit waktu untuk memahami cara kerja metode yang mendasarinya, lalu sediakan. Jadi, Anda memiliki kendali penuh atas kode, dan Anda dapat menjamin bahwa dengan seed yang sama, urutannya akan selalu persis sama, terlepas dari platform atau versi C ++ yang Anda tautkan.
sumber