Il me semble voir de nombreuses réponses dans lesquelles quelqu'un suggère d'utiliser <random>
pour générer des nombres aléatoires, généralement avec un code comme celui-ci:
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, 5);
dis(gen);
Habituellement, cela remplace une sorte d '«abomination impie» telle que:
srand(time(NULL));
rand()%6;
Nous pourrions critiquer l'ancienne méthode en affirmant qu'elle time(NULL)
fournit une faible entropie, qu'elle time(NULL)
est prévisible et que le résultat final n'est pas uniforme.
Mais tout cela est vrai de la nouvelle façon: il a juste un placage plus brillant.
rd()
renvoie un seulunsigned int
. Cela a au moins 16 bits et probablement 32. Cela ne suffit pas pour amorcer les bits d'état 19937 de MT.Utiliser
std::mt19937 gen(rd());gen()
(ensemencer avec 32 bits et regarder la première sortie) ne donne pas une bonne distribution de sortie. 7 et 13 ne peuvent jamais être la première sortie. Deux graines produisent 0. Douze graines produisent 1226181350. ( Lien )std::random_device
peut être, et est parfois, implémenté comme un simple PRNG avec une graine fixe. Il peut donc produire la même séquence à chaque exécution. ( Lien ) C'est encore pire quetime(NULL)
.
Pire encore, il est très facile de copier et coller les extraits de code précédents, malgré les problèmes qu'ils contiennent. Certaines solutions à cela nécessitent l'acquisition de grandes bibliothèques qui peuvent ne pas convenir à tout le monde.
À la lumière de cela, ma question est: Comment peut-on semer succinctement, de manière portable et complète le PRNG mt19937 en C ++?
Compte tenu des problèmes ci-dessus, une bonne réponse:
- Doit semer complètement le mt19937 / mt19937_64.
- Ne peut pas compter uniquement sur
std::random_device
outime(NULL)
comme source d'entropie. - Ne devrait pas compter sur Boost ou d'autres bibliothèques.
- Doit tenir dans un petit nombre de lignes de sorte que cela semble bien copié-collé dans une réponse.
Pensées
Ma pensée actuelle est que les sorties de
std::random_device
peuvent être mélangées (peut-être via XOR) avec destime(NULL)
valeurs dérivées de la randomisation de l'espace d'adressage et une constante codée en dur (qui pourrait être définie lors de la distribution) pour obtenir un meilleur effort d'entropie.std::random_device::entropy()
ne donne pas une bonne indication de ce quistd::random_device
pourrait ou ne pourrait pas faire.
std::random_device
, time(NULL)
et des adresses de fonction, puis XORed ensemble pour produire une sorte de source d'entropie au mieux.
std::random_device
correctement sur les plates-formes sur lesquelles vous prévoyez d'exécuter votre programme et à fournir une fonction d'assistance qui crée un générateur prédéfini ( seed11::make_seeded<std::mt19937>()
)