125 votes

Générer des nombres aléatoires suivant une loi normale en C/C++

Quelqu'un sait-il comment je pourrais facilement générer des nombres aléatoires suivant une loi normale en C/C++ ?

http://www.MathWorks.com/Access/helpdesk/Help/Toolbox/stats/normrnd.html

Je ne veux pas utiliser un Boost.

Je sais que Knuth pourparlers à ce sujet en détail, mais je n’ai pas de ses livres à portée de main dès maintenant.

98voto

S.Lott Points 207588

Le Box-Muller transformer, c'est ce qui est couramment utilisée. Ce produit correctement les valeurs avec une distribution normale.

http://en.wikipedia.org/wiki/Normal_distribution#Generating_values_from_normal_distribution

http://en.wikipedia.org/wiki/Box_Muller_transform

Le calcul est facile. Vous générez deux uniformes de chiffres et de ceux que vous obtenez deux normalement distribué des nombres. De retour de l'un, l'autre pour la prochaine demande d'un nombre aléatoire.

51voto

Peter G. Points 8566

EDIT: Depuis le 12 août 2011, nous avons C++11 qui offre directement std::normal_distribution, ce qui est la façon dont je voudrais aller aujourd'hui.

Voici l'original de la réplique:

Voici quelques solutions ordonnées par ordre croissant de complexité.

  1. Ajouter 12 uniforme des nombres entre 0 et 1 et soustraire 6. Ceci correspondra à la moyenne et l'écart type d'une variable normale. Un inconvénient évident est que la gamme est limitée à +/-6 - à la différence d'une vraie distribution normale.

  2. De Box-Muller transformer - a été énumérés ci-dessus, et est relativement simple à mettre en œuvre. Si vous avez besoin très précis des échantillons toutefois, sachez que le Box-Muller transformer combiné avec certains uniforme générateurs souffre d'une anomalie appelée Neave Effet.

    H. R. Neave, "Sur l'utilisation de la Boîte-Muller transformation avec multiplicatif de congruence des générateurs de nombres pseudo-aléatoires," Statistique Appliquée, 22, 92-97, 1973

  3. Pour une meilleure précision , je suggère le dessin d'uniformes et de l'application de l'inverse de la distribution normale cumulative pour arriver à une distribution normale variates. Vous pouvez trouver un très bon algorithme pour l'inverse de la distribution normale cumulative d'au

http://home.online.no/~pjacklam/notes/invnorm/#vue d'ensemble

Espère que ça aide

Peter

31voto

Paul R Points 104036

Une méthode rapide et facile est juste pour résumer un certain nombre de nombres aléatoires distribués uniformément et prendre leur moyenne. Voir le Théorème de la limite centrale pour une explication complète de pourquoi cela fonctionne.

14voto

Pete855217 Points 788

Voici un exemple C ++, basé sur certaines des références. C'est rapide et sale, il vaut mieux ne pas réinventer et utiliser la bibliothèque boost.

 #include "math.h" // for RAND, and rand
double sampleNormal() {
    double u = ((double) rand() / (RAND_MAX)) * 2 - 1;
    double v = ((double) rand() / (RAND_MAX)) * 2 - 1;
    double r = u * u + v * v;
    if (r == 0 || r > 1) return sampleNormal();
    double c = sqrt(-2 * log(r) / r);
    return u * c;
}
 

Vous pouvez utiliser un graphique QQ pour examiner les résultats et voir dans quelle mesure il se rapproche d'une distribution normale réelle (classez vos échantillons 1..x, transformez les rangs en proportions du nombre total de x, c'est-à-dire combien d'échantillons, obtenez les valeurs z. et tracez-les. Une ligne droite ascendante est le résultat souhaité).

12voto

Joe Gauterin Points 9526

Utilisation `` .

L’espace de noms std::tr1 n’est pas une partie de la Poussée. C’est l’espace de noms qui contient les ajouts de la bibliothèque de 1 rapport technique C++ et est disponible dans les compilateurs Microsoft à jour et de la gcc, indépendamment de Poussée.

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