C++
Génération de nombres aléatoires
Recherche…
Remarques
La génération de nombres aléatoires en C ++ est fournie par l’en-tête <random>
. Cet en-tête définit des périphériques aléatoires, des générateurs pseudo-aléatoires et des distributions.
Les périphériques aléatoires renvoient des nombres aléatoires fournis par le système d'exploitation. Ils doivent être utilisés soit pour l'initialisation de générateurs pseudo-aléatoires, soit directement pour des besoins cryptographiques.
Les générateurs pseudo-aléatoires renvoient des nombres pseudo-aléatoires entiers basés sur leur graine initiale. La plage de nombres pseudo-aléatoires couvre généralement toutes les valeurs d'un type non signé. Tous les générateurs pseudo-aléatoires de la bibliothèque standard renverront les mêmes numéros pour la même graine initiale pour toutes les plates-formes.
Les distributions consomment des nombres aléatoires de générateurs pseudo-aléatoires ou de dispositifs aléatoires et produisent des nombres aléatoires avec la distribution nécessaire. Les distributions ne sont pas indépendantes de la plate-forme et peuvent produire des nombres différents pour les mêmes générateurs avec les mêmes semences initiales sur différentes plates-formes.
Véritable générateur de valeur aléatoire
Pour générer de vraies valeurs aléatoires pouvant être utilisées pour la cryptographie, std::random_device
doit être utilisé comme générateur.
#include <iostream>
#include <random>
int main()
{
std::random_device crypto_random_generator;
std::uniform_int_distribution<int> int_distribution(0,9);
int actual_distribution[10] = {0,0,0,0,0,0,0,0,0,0};
for(int i = 0; i < 10000; i++) {
int result = int_distribution(crypto_random_generator);
actual_distribution[result]++;
}
for(int i = 0; i < 10; i++) {
std::cout << actual_distribution[i] << " ";
}
return 0;
}
std::random_device
est utilisé de la même manière qu'un générateur de valeur pseudo-aléatoire est utilisé.
Cependant, std::random_device
peut être implémenté en termes de moteur de nombres pseudo-aléatoires défini par l'implémentation si une source non déterministe (par exemple un périphérique matériel) n'est pas disponible pour l'implémentation.
La détection de telles implémentations devrait être possible via la fonction membre entropy
(qui retourne zéro lorsque le générateur est totalement déterministe), mais de nombreuses bibliothèques populaires (libstdc ++ et libc ++ de LLVM) renvoient toujours zéro, même lorsqu'elles utilisent un caractère aléatoire externe de haute qualité. .
Générer un nombre pseudo-aléatoire
Un générateur de nombres pseudo-aléatoires génère des valeurs qui peuvent être devinées en fonction des valeurs précédemment générées. En d'autres termes: c'est déterministe. N'utilisez pas de générateur de nombres pseudo-aléatoires dans les cas où un nombre aléatoire réel est requis.
#include <iostream>
#include <random>
int main()
{
std::default_random_engine pseudo_random_generator;
std::uniform_int_distribution<int> int_distribution(0, 9);
int actual_distribution[10] = {0,0,0,0,0,0,0,0,0,0};
for(int i = 0; i < 10000; i++) {
int result = int_distribution(pseudo_random_generator);
actual_distribution[result]++;
}
for(int i = 0; i <= 9; i++) {
std::cout << actual_distribution[i] << " ";
}
return 0;
}
Ce code crée un générateur de nombres aléatoires et une distribution qui génère des nombres entiers dans la plage [0,9] avec une probabilité égale. Il compte ensuite combien de fois chaque résultat a été généré.
Le paramètre template de std::uniform_int_distribution<T>
spécifie le type d'entier à générer. Utilisez std::uniform_real_distribution<T>
pour générer des flottants ou des doubles.
Utilisation du générateur pour plusieurs distributions
Le générateur de nombres aléatoires peut (et devrait) être utilisé pour plusieurs distributions.
#include <iostream>
#include <random>
int main()
{
std::default_random_engine pseudo_random_generator;
std::uniform_int_distribution<int> int_distribution(0, 9);
std::uniform_real_distribution<float> float_distribution(0.0, 1.0);
std::discrete_distribution<int> rigged_dice({1,1,1,1,1,100});
std::cout << int_distribution(pseudo_random_generator) << std::endl;
std::cout << float_distribution(pseudo_random_generator) << std::endl;
std::cout << (rigged_dice(pseudo_random_generator) + 1) << std::endl;
return 0;
}
Dans cet exemple, un seul générateur est défini. Il est ensuite utilisé pour générer une valeur aléatoire dans trois distributions différentes. La distribution rigged_dice
va générer une valeur comprise entre 0 et 5, mais génère presque toujours un 5
, car la chance de générer un 5
est de 100 / 105
.