J'ai rouge tout ce qui précède, environ 40 autres pages contenant du c ++ comme ça et j'ai regardé la vidéo de Stephan T. Lavavej "STL"
et je n'étais toujours pas sûr du fonctionnement des nombres aléatoires dans la praxis, alors j'ai pris un dimanche complet pour comprendre de quoi il s'agit et comment il fonctionne et peut être utilisé.
À mon avis, STL a raison de "ne plus utiliser srand" et il l'a bien expliqué dans la vidéo 2 . Il recommande également d'utiliser:
a) void random_device_uniform()
- pour une génération chiffrée mais plus lente (d'après mon exemple)
b) les exemples avec mt19937
- plus rapide, possibilité de créer des graines, non chiffrés
J'ai sorti tous les livres c ++ 11 revendiqués auxquels j'ai accès et j'ai découvert que des auteurs allemands comme Breymann (2015) utilisent toujours un clone de
srand( time( 0 ) );
srand( static_cast<unsigned int>(time(nullptr))); or
srand( static_cast<unsigned int>(time(NULL))); or
juste avec <random>
au lieu de <time> and <cstdlib>
#includings - alors faites attention à n'apprendre qu'à partir d'un seul livre :).
Cela signifie - cela ne devrait pas être utilisé depuis C ++ 11 car:
Les programmes ont souvent besoin d'une source de nombres aléatoires. Avant la nouvelle norme, C et C ++ reposaient sur une simple fonction de bibliothèque C nommée rand. Cette fonction produit des entiers pseudo-aléatoires qui sont uniformément distribués dans la plage de 0 à une valeur maximale dépendante du système qui est d'au moins 32767. La fonction rand pose plusieurs problèmes: de nombreux programmes, sinon la plupart, ont besoin de nombres aléatoires dans une plage différente de celle un produit par rand. Certaines applications nécessitent des nombres à virgule flottante aléatoires. Certains programmes ont besoin de nombres qui reflètent une distribution non uniforme. Les programmeurs introduisent souvent un caractère non aléatoire lorsqu'ils tentent de transformer la plage, le type ou la distribution des nombres générés par rand. (citation de Lippmans C ++ primer cinquième édition 2012)
J'ai finalement trouvé la meilleure explication parmi 20 livres dans les plus récents de Bjarne Stroustrups - et il devrait connaître son affaire - dans «A tour of C ++ 2019», «Programming Principles and Practice Using C ++ 2016» et «The C ++ Programming Language 4ème édition 2014 "et aussi quelques exemples dans" Lippmans C ++ primer cinquième édition 2012 ":
Et c'est vraiment simple car un générateur de nombres aléatoires se compose de deux parties:
(1) un moteur qui produit une séquence de valeurs aléatoires ou pseudo-aléatoires. (2) une distribution qui mappe ces valeurs dans une distribution mathématique dans une plage.
Malgré l'avis du gars de Microsofts STL, Bjarne Stroustrups écrit:
Dans, la bibliothèque standard fournit des moteurs de nombres aléatoires et des distributions (§24.7). Par défaut, utilisez le default_random_engine, qui est choisi pour une large applicabilité et un faible coût.
L' void die_roll()
exemple est de Bjarne Stroustrups - bonne idée de génération de moteur et de distribution avec using
(plus de détails ici) .
Pour pouvoir utiliser concrètement les générateurs de nombres aléatoires fournis par la bibliothèque standard, voici un code exécutable avec différents exemples réduits au minimum nécessaire qui, espérons-le, vous feront gagner du <random>
temps et de l'argent:
#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;
}
Je pense que cela ajoute tout cela et comme je l'ai dit, il m'a fallu beaucoup de lecture et de temps pour le décrire à ces exemples - si vous avez d'autres informations sur la génération de nombres, je suis heureux d'en entendre parler via pm ou dans la section des commentaires et l'ajoutera si nécessaire ou modifiera cet article. Booléen