117 votes

Génération de nombres aléatoires en C++11 : comment générer, comment ça marche ?

J'ai récemment découvert une nouvelle façon de générer des nombres aléatoires en C++11, mais je n'ai pas réussi à digérer l'explication de cette méthode. documents que j'ai lu à ce sujet (qu'est-ce que c'est moteur , terme de maths comme distribution où tous les nombres entiers produits sont aussi probable ").

Quelqu'un peut-il m'expliquer

  • qu'est-ce que c'est ?
  • que signifient-ils ?
  • comment générer ?
  • comment fonctionnent-ils ?
  • etc.

Vous pouvez tout appeler dans une FAQ sur la génération de nombres aléatoires.

158voto

Kerrek SB Points 194696

La question est bien trop vaste pour qu'on puisse y répondre complètement, mais permettez-moi de sélectionner quelques points intéressants :

Pourquoi "également probable"

Supposons que vous disposiez d'un générateur de nombres aléatoires simple qui génère les nombres 0, 1, ..., 10, chacun avec une probabilité égale (pensez à cela comme au classique rand() ). Vous souhaitez maintenant obtenir un nombre aléatoire compris dans l'intervalle 0, 1, 2, chacun avec une probabilité égale. Votre réaction instinctive serait de prendre rand() % 3 . Mais attendez, les restes 0 et 1 se produisent plus souvent que le reste 2, donc ce n'est pas correct !

C'est pourquoi nous avons besoin de distributions qui prennent une source d'entiers aléatoires uniformes et les transforment en la distribution souhaitée, comme par exemple Uniform[0,2] dans l'exemple. Il est préférable de confier cette tâche à une bonne bibliothèque !

Moteurs

Ainsi, au cœur de tout caractère aléatoire se trouve un bon générateur de nombres pseudo-aléatoires qui génère une séquence de nombres uniformément répartis sur un certain intervalle, et qui ont idéalement une très longue période. L'implémentation standard de rand() n'est pas souvent le meilleur, et il est donc bon d'avoir le choix. La méthode linéaire-congruentielle et le tordeur de Mersenne sont deux bons choix (LG est en fait souvent utilisé par rand() ) ; là encore, il est préférable de laisser la bibliothèque s'en charger.

Comment cela fonctionne

Facile : d'abord, configurer un moteur et l'ensemencer. Le germe détermine entièrement la séquence entière de nombres "aléatoires", donc a) utilisez-en un autre (par exemple, tiré de /dev/urandom ) à chaque fois, et b) stocker la graine si vous souhaitez recréer une séquence de choix aléatoires.

#include <random>

typedef std::mt19937 MyRNG;  // the Mersenne Twister with a popular choice of parameters
uint32_t seed_val;           // populate somehow

MyRNG rng;                   // e.g. keep one global instance (per thread)

void initialize()
{
  rng.seed(seed_val);
}

Maintenant, nous pouvons créer des distributions :

std::uniform_int_distribution<uint32_t> uint_dist;         // by default range [0, MAX]
std::uniform_int_distribution<uint32_t> uint_dist10(0,10); // range [0,10]
std::normal_distribution<double> normal_dist(mean, stddeviation);  // N(mean, stddeviation)

...Et utiliser le moteur pour créer des nombres aléatoires !

while (true)
{
  std::cout << uint_dist(rng) << " "
            << uint_dist10(rng) << " "
            << normal_dist(rng) << std::endl;

}

Concurrence

Une raison supplémentaire de préférer <random> par rapport au traditionnel rand() est qu'il est maintenant très clair et évident de rendre la génération de nombres aléatoires threadsafe : Il faut soit fournir à chaque thread son propre moteur, local au thread, avec une graine locale au thread, soit synchroniser l'accès à l'objet moteur.

Divers

  • Un site article intéressant sur TR1 aléatoire sur codeguru.
  • Wikipedia a un bon résumé (merci, @Justin).
  • En principe, chaque moteur devrait typedef un result_type qui est le type d'intégrale correct à utiliser pour la graine. Je pense que j'ai eu une fois une implémentation boguée qui m'a forcé à forcer la graine de std::mt19937 à uint32_t sur x64, éventuellement cela devrait être corrigé et vous pourrez dire MyRNG::result_type seed_val et rendre ainsi le moteur très facilement remplaçable.

5voto

mydogisbox Points 13272

Un générateur de nombres aléatoires est une équation qui, étant donné un nombre, vous donnera un nouveau nombre. En général, soit vous fournissez le premier nombre, soit il est tiré de quelque chose comme l'heure du système.

Chaque fois que vous demandez un nouveau nombre, il utilise le nombre précédent pour exécuter l'équation.

Un générateur de nombres aléatoires n'est pas considéré comme très bon s'il a tendance à produire le même nombre plus souvent que d'autres. Par exemple, si vous voulez un nombre aléatoire entre 1 et 5 et que vous avez cette distribution de nombres :

  • 1 : 1%
  • 2 : 80%
  • 3 : 5%
  • 4 : 5%
  • 5 : 9%

Le 2 est généré beaucoup plus souvent que n'importe quel autre nombre, il est donc plus susceptible d'être produit que les autres nombres. Si tous les nombres étaient identiques, vous auriez 20 % de chances d'obtenir chaque nombre à chaque fois. En d'autres termes, la distribution ci-dessus est très inégale car le 2 est favorisé. Une distribution avec tous les 20% serait égale.

En général, si vous voulez un véritable nombre aléatoire, vous devez tirer des données de quelque chose comme la météo ou une autre source naturelle plutôt qu'un générateur de nombres aléatoires.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X