Ho scritto tutto sopra, circa 40 altre pagine con c ++ in questo modo e guardato il video di Stephan T. Lavavej "STL"
e non ero ancora sicuro di come i numeri casuali funzionino nella prassi, quindi ho impiegato un'intera domenica per capire di cosa si tratta e come funziona e può essere utilizzato.
Secondo me STL ha ragione sul "non usare più srand" e lo ha spiegato bene nel video 2 . Inoltre consiglia di utilizzare:
a) void random_device_uniform()
- per generazione crittografata ma più lenta (dal mio esempio)
b) gli esempi con mt19937
- più veloce, capacità di creare semi, non crittografati
Ho tirato fuori tutti i libri di c ++ 11 a cui ho accesso e ho scoperto che autori tedeschi come Breymann (2015) usano ancora un clone di
srand( time( 0 ) );
srand( static_cast<unsigned int>(time(nullptr))); or
srand( static_cast<unsigned int>(time(NULL))); or
solo con <random>
invece di <time> and <cstdlib>
#includings - quindi fai attenzione a imparare solo da un libro :).
Significato: non dovrebbe essere usato da c ++ 11 perché:
I programmi hanno spesso bisogno di una fonte di numeri casuali. Prima del nuovo standard, sia C che C ++ si basavano su una semplice funzione di libreria C denominata rand. Questa funzione produce numeri interi pseudocasuali distribuiti uniformemente nell'intervallo da 0 a un valore massimo dipendente dal sistema che è almeno 32767. La funzione rand presenta diversi problemi: molti, se non la maggior parte, i programmi richiedono numeri casuali in un intervallo diverso da uno prodotto da Rand. Alcune applicazioni richiedono numeri casuali in virgola mobile. Alcuni programmi richiedono numeri che riflettano una distribuzione non uniforme. I programmatori spesso introducono la non casualità quando provano a trasformare l'intervallo, il tipo o la distribuzione dei numeri generati da Rand. (citazione da Lippmans C ++ primer quinta edizione 2012)
Alla fine ho trovato la migliore spiegazione tra i 20 libri di Bjarne Stroustrups e quelli più recenti - e dovrebbe conoscere le sue cose - in "Un tour di C ++ 2019", "Principi di programmazione e pratica usando C ++ 2016" e "La quarta edizione del linguaggio di programmazione C ++ 2014 "e anche alcuni esempi in" Lippmans C ++ primer 5th edition 2012 ":
Ed è davvero semplice perché un generatore di numeri casuali è composto da due parti:
(1) un motore che produce una sequenza di valori casuali o pseudo-casuali. (2) una distribuzione che mappa quei valori in una distribuzione matematica in un intervallo.
Nonostante l'opinione del ragazzo di Microsofts STL, Bjarne Stroustrups scrive:
In, la libreria standard fornisce motori e distribuzioni di numeri casuali (§24.7). Per impostazione predefinita, utilizzare default_random_engine, scelto per ampia applicabilità e basso costo.
L' void die_roll()
esempio è di Bjarne Stroustrups - buona idea per generare motore e distribuzione con using
(più di quello qui) .
Per essere in grado di fare un uso pratico dei generatori di numeri casuali forniti dalla libreria standard <random>
qui alcuni codici eseguibili con diversi esempi ridotti al minimo necessario che speriamo di risparmiare tempo e denaro per voi ragazzi:
#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;
}
Penso che aggiunga tutto e come ho detto, mi ci sono voluti un sacco di letture e tempo per dirlo a quegli esempi - se hai altre cose sulla generazione di numeri, sono felice di sentirlo via pm o nella sezione commenti e lo aggiungerà se necessario o modificherà questo post. Bool