Así que rand()
est un générateur de nombres pseudo-aléatoires qui choisit un nombre naturel entre 0 et RAND_MAX
qui est une constante définie dans cstdlib
(voir ce article pour un aperçu général sur rand()
).
Maintenant, que se passe-t-il si vous voulez générer un nombre aléatoire entre, disons, 0 et 2 ? Pour les besoins de l'explication, disons que RAND_MAX
est 10 et je décide de générer un nombre aléatoire entre 0 et 2 en appelant rand()%3
. Cependant, rand()%3
ne produit pas les nombres entre 0 et 2 avec la même probabilité !
Quand rand()
renvoie 0, 3, 6 ou 9, rand()%3 == 0
. Par conséquent, P(0) = 4/11
Quand rand()
renvoie 1, 4, 7 ou 10, rand()%3 == 1
. Par conséquent, P(1) = 4/11
Quand rand()
renvoie 2, 5 ou 8, rand()%3 == 2
. Par conséquent, P(2) = 3/11
Cela ne génère pas les nombres entre 0 et 2 avec une probabilité égale. Bien sûr, pour les petites fourchettes, ce n'est peut-être pas le plus gros problème, mais pour une fourchette plus large, cela pourrait fausser la distribution, en biaisant les petits nombres.
Alors, quand est-ce que rand()%n
retourner une plage de nombres de 0 à n-1 avec une probabilité égale ? Lorsque RAND_MAX%n == n - 1
. Dans ce cas, avec notre hypothèse précédente rand()
renvoie un nombre entre 0 et RAND_MAX
avec une probabilité égale, les classes modulo de n seraient également distribuées de manière égale.
Alors comment résoudre ce problème ? Une méthode rudimentaire consiste à générer des nombres aléatoires jusqu'à ce que vous obteniez un nombre dans la fourchette souhaitée :
int x;
do {
x = rand();
} while (x >= n);
mais c'est inefficace pour les faibles valeurs de n
puisque vous n'avez qu'un n/RAND_MAX
chance d'obtenir une valeur dans votre fourchette, et vous devrez donc effectuer RAND_MAX/n
appels à rand()
en moyenne.
Une formule plus efficace consisterait à prendre une grande plage dont la longueur est divisible par n
comme RAND_MAX - RAND_MAX % n
Pour cela, continuez à générer des nombres aléatoires jusqu'à ce que vous en obteniez un qui se situe dans l'intervalle, puis prenez le module :
int x;
do {
x = rand();
} while (x >= (RAND_MAX - RAND_MAX % n));
x %= n;
Pour de petites valeurs de n
ce qui nécessitera rarement plus d'un appel à la fonction rand()
.
Ouvrages cités et lectures complémentaires :