page perso
Programmation
Générateur pseudo-aléatoire

Dans le cadre d'une simulation, il est important d'avoir un bon générateur de nombres pseudo-aléatoires. Cependant, il est tout aussi important de ne pas faire n'importe quoi avec. Il faut initialiser la graine avec une valeur connue (reproductible), il ne faut pas utiliser un générateur pour en faire plusieurs, ou ils seront corrélés... Bref, le cadre de travail est exigeant.
Grâce à la syntaxe du C++, j'ai pu écrire une classe Random bien utile, puisqu'elle fournit un bon générateur (trouvé dans les numerical recipes - à savoir le générateur de l'Ecuyer avec mélange de Bays-Durham), et assez bien interfacé pour le rendre pratique et rigoureux à la fois.
Et c'est bien là le but des fichiers sources disponibles sur cette page : non pas fournir un générateur développé en amateur, mais une interface correcte pour en faire bon usage. De plus, il ne s'agit pas de 30 fichiers sources incompilables ailleurs que chez moi, mais d'une toute petite classe en C++ aussi standard possible. Il n'y a aucun warning avec gcc 3.3 et les options -Wall -ansi -pedantic.

  • L'encapsulation permet de masquer le "noyau" de génération et de ne rendre apparentes que des fonctions utilisables:
    • Random::Uniform<T>(T min,T max) pour une distribution Uniforme, où T est un type quelconque (double, int, etc...).
    • Random::Gaussian(moyenne, ecartype) pour une distribution Gaussienne.
    • Random::Exponential(lambda) pour une distribution Exponentielle.
    • Random::Randomize(graine) pour réinitialiser la graine.
  • Je fournis deux versions du générateur : l'une (conseillée) utilise le pattern Singleton pour garantir l'unicité du générateur dans le code. Il n'y a qu'une seule graine et une seule suite pseudo-aléatoire.
    L'autre fournit le générateur comme un objet autonome. On peut donc en avoir plusieurs, "indépendants", dans le programme, chacun possédant sa graine. Mais rien ne guarantit la non-corrélation.
Il n'y a aucun droit Copyright ou Copyleft attaché aux fichiers que je vous fournis pour ce générateur. Vous pouvez réutiliser le code et le modifier, le distribuer à votre guise. Mais gardez une trace et une paternité des modifications.
Ci-dessous se trouvent quelques mises en situation montrant grossièrement la validité de l'implémentation, à partir de plusieurs milliers de tirages comparés à la distribution réelle attendue.
 
 
Téléchargement
Version Singleton
Voir le fichier d'en-tête : random-singleton.h (4Ko)
Voir le fichier d'implémentation : random-singleton.cpp (4Ko)
Voir un exemple d'utilisation : random-demonstration-singleton.cpp (4Ko)
Archive du total : random-singleton.zip (4Ko)

Version Autonome
Voir le fichier d'en-tête : random-standalone.h (4Ko)
Voir le fichier d'implémentation : random-standalone.cpp (4Ko)
Voir un exemple d'utilisation : random-demonstration-standalone.cpp (4Ko)
Archive du total : random-standalone.zip (4Ko)
 
 
Loi Uniforme
Nombre entier uniforme dans [|0;100|]
Random::Uniform<int>(0,100)
Génération uniforme dans [|0;100|]
Moyenne attendue :50,
Moyenne observée: 50.0838,
Ecartype observé: 29.0984

Nombre réel uniforme dans [0;1]
Random::Uniform<double>(0,1)
Génération uniforme dans [0;1]
Moyenne attendue: 0.5,
Moyenne observée: 0.500823,
Ecartype observé: 0.288113
 
 
Loi Gaussienne
Notez bien qu'il sagit de N(mu,sigma) et NON de N(mu,sigma^2).

Gaussienne(moyenne=1.234, ecartype=5.678)
Random::Gaussian(1.234, 5.678)
Répartition de génération gaussienne de moyenne 1.234 et d'écartype 5.678
Moyenne observée: 1.23639,
Ecartype observé: 5.67899
 
 
Loi Exponentielle
-1/lambda*log(y) où "y" suit une loi uniforme dans [0;1]

Exponentielle(lambda=2)
Random::Exponential(lambda=2)
Répartition de génération exponentielle de paramètre 2
Moyenne observée:0.502966,
Ecartype observé:0.511291
 
 
Performances

Les performances du générateur standard du C sont très variables selon les systèmes, la version du compilateur, comme le montrent les graphiques ci-après. Les tests effectués ne sont pas très pertinents, mais permettent de se faire une idée de l'impact sur les temps de calcul de l'utilisation du générateur que je vous fournis.

Globalement, le générateur standard rand() est plus rapide, on pouvait s'y attendre. Mais avec des options d'optimisation, les performances du générateur que je vous fournis restent très honorables en comparaison, surtout vu le gain en propreté et en garanties.

Les temps indicatifs donnés dans le graphique ci-dessous ont été calculés grâce à un programme effectuant 100 000 000 tirages avec un "(float)rand()/RAND_MAX", puis 100 000 000 tirages avec un "Random::Uniform()". Lancé plusieurs fois d'affilée, le programme avait des temps d'exécution stables, à moins d'une seconde près.

Performances 1
Performances 2
 
 

PHP MySQL Valid CSS!