1.6- Génération de nombres aléatoires
1- Le générateur aléatoire disponible en C++
2 – Création d'un générateur aléatoire uniforme sur un intervalle
3- Génération de valeurs aléatoires selon une loi normale
4- Génération de valeurs aléatoire selon une distribution ad hoc
5- Génération d'un ordre aléatoire
On introduit des fonctions aléatoires classiques pour lesquelles on fournit ensuite un fichier qui les implémente.
1 Le générateur aléatoire disponible en C++
Génération de valeurs aléatoires
En toute rigueur, dans ce qui suit, on devrait parler de génération de nombres pseudo-aléatoires.
Les fonctions nécessaires à la génération aléatoire sont contenues dans la librairie <cstdlib>. La génération de nombres
aléatoires implique d'abord d'initialiser la racine (seed) par l'instruction :
srand(time(0));
time est une fonction de la librairie <ctime> : sans entrer dans les détails, time(0) est la date du jour exprimée en nombre de
secondes depuis le 1er janvier 1970. Le chiffre va permettre d'initialiser une séquence de nombres pseudo-aléatoires. Tous les
programmes qui comprennent la génération de nombres aléatoires contiendront cette instruction ou des instructions
d'initialisation de la racine des nombres aléatoires, celle qui est présentée ici étant la plus utilisée.
Par suite, on utilise la fonction rand() qui renvoie (selon un tirage uniforme) un nombre entier entre 0 et un entier maximal
susceptible de varier en fonction des implémentations. Un premier exemple de génération de nombre aléatoire :
#include <cstdlib>
#include <ctime>
#include <iostream>
int main(){
srand(time(0));
for(int i=0;i<5;i++)
std::cout << "Nombre aleatoire : " << rand() << "\n";
}
Les nombres qui sont tirés sont entre 0 et RAND_MAX (inclus) qui est une constante entière définie dans <cstdlib>.
Tirage de valeurs aléatoires selon une loi uniforme sur [0:1]
Pour tirer des nombres aléatoires compris dans [0:1] :
#include <cstdlib>
#include <ctime>
#include <iostream>
int main(){
srand(time(0));
for(int i=0;i<5;i++)
std::cout << "Nombre aleatoire : " << rand()/(double)RAND_MAX << "\n";
}
On peut donc créer une fonction de génération de nombres aléatoires selon une loi uniforme sur [0:1] :
#include <cstdlib>
#include <ctime>
#include <iostream>
double randomUniform()
{
return rand()/(double)RAND_MAX;
}
int main(){
srand(time(0));
for(int i=0;i<5;i++)
std::cout << "Nombre aleatoire : " << randomUniform() << "\n";
}
2 Création d'un générateur aléatoire uniforme sur un intervalle
Tirage uniforme de réels sur un intervalle quelconque
A partir de la fonction randomUniform() qui a été définie plus haut, on peut définir une fonction plus complexe qui tire des
valeurs aléatoires dans un intervalle [a:b] de réels. Pour se faire, on surcharge la fonction randomUniform en passant des
paramètres d'intervalle :
#include <cstdlib>
#include <ctime>
double randomUniform()
{
return rand()/(double)RAND_MAX;
}
double randomUniform(double a,double b)
{
return (b-a)*randomUniform()+a;
}
Cette fonction fait bien ce qui a été annoncé :
tirageAleatoireUniforme01() est tiré dans [0:1]
Donc (b-a)*tirageAleatoireUniforme01() est dans [0;b-a]
Donc (b-a)*tirageAleatoireUniforme01()+a est dans [a;b]
Note : la fonction randomUniform(double a,double b) s'exécutera quand même, même si a>b. On pourrait envisager une
fonction plus complexe qui ne s'exécuterait qu'à la condition que a<=b.
Tirage uniforme d'entiers sur un intervalle quelconque
Pour tirer des entiers dans [0;n-1], on pourrait produire une fonction assez rapidement :
int randomInteger(int n)
{
return rand()%n;
}
Certes, il est évident que la fonction renvoie des entiers dans [0:n-1]. Néanmoins, cette fonction est biaisée. En effet,
supposons que RAND_MAX soit 10 et que l'on veuille faire un tirage sur [0:2], ie avec n=3. Comme RAND_MAX est 10, cela
signifie que les valeurs que rand() peut renvoyer sont 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 et 10.
Lorsque rand() renvoie 0, 3, 6, 9, randomInteger() renvoie 0.
Lorsque rand() renvoie 1, 4, 7, 10, randomInteger() renvoie 1.
Lorsque rand() renvoie 2, 5, 8, randomInteger() renvoie 2.
Donc la fonction renvoie 0 avec une probabilité 4/11, 1 avec une probabilité 4/11 et 2avec une probabilité 3/11. Donc la fonction
ne tire pas les entiers de manière uniforme sur [0:2], sauf dans le cas où RAND_MAX est un entier premier (à vérifier).
Pour tirer des entiers de manière uniforme, on préférera une fonction de la forme randomInteger ci dessous :
#include <cstdlib>
#include <ctime>
#include <iostream>
double randomUniform()
{
return rand()/(double)RAND_MAX;
}
double randomUniform(double a,double b)
{
return (b-a)*randomUniform()+a;
}
long arrondir(double x)//arrondi à l'entier le plus proche
{
long a=(long)x;
if(a+0.5<=x)
return a+1;
else
return a;
}
long randomInteger(long a,long b)
{
double x=randomUniform(a-0.5,b+0.5);
return arrondir(x);
}
int main(){
srand(time(0));
long a=20;
long b=40;
unsigned long nombreTests=1000000;
unsigned long compte[b+1];
for(int i=0;i<=b;i++)
{
compte[i]=0;
}
for(int i=0;i<nombreTests;i++)
{
compte[randomInteger(a,b)]++;
}
double somme=0;
for(int i=0;i<=b;i++)
{
double x=compte[i]/(double)nombreTests;
somme+=x;
std::cout << i << " " << x << "\n";
}
std::cout << "La somme : " << somme << "\n";
1 / 13 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !