Toutes les réponses à ce jour sont mathématiquement fausses. Le retour rand() % N
ne donne pas uniformément un nombre dans la plage à [0, N)
moins de N
diviser la longueur de l'intervalle dans lequel rand()
renvoie (c'est-à-dire une puissance de 2). De plus, on ne sait pas si les modules de rand()
sont indépendants: il est possible qu'ils disparaissent 0, 1, 2, ...
, ce qui est uniforme mais pas très aléatoire. La seule hypothèse qu'il semble raisonnable de faire est celle qui rand()
émet une distribution de Poisson: deux sous-intervalles non chevauchants de même taille sont également probables et indépendants. Pour un ensemble fini de valeurs, cela implique une distribution uniforme et garantit également que les valeurs de rand()
sont bien dispersées.
Cela signifie que la seule façon correcte de modifier la plage de rand()
est de la diviser en cases; par exemple, si RAND_MAX == 11
et vous voulez une plage de 1..6
, vous devez attribuer {0,1}
à 1, {2,3}
à 2, et ainsi de suite. Ce sont des intervalles disjoints, de taille égale et donc distribués uniformément et indépendamment.
La suggestion d'utiliser la division en virgule flottante est mathématiquement plausible mais souffre en principe de problèmes d'arrondi. La double
précision est peut -être suffisamment élevée pour que cela fonctionne; peut-être pas. Je ne sais pas et je ne veux pas avoir à le comprendre; dans tous les cas, la réponse dépend du système.
La bonne façon est d'utiliser l'arithmétique des nombres entiers. Autrement dit, vous voulez quelque chose comme ce qui suit:
#include <stdlib.h> // For random(), RAND_MAX
// Assumes 0 <= max <= RAND_MAX
// Returns in the closed interval [0, max]
long random_at_most(long max) {
unsigned long
// max <= RAND_MAX < ULONG_MAX, so this is okay.
num_bins = (unsigned long) max + 1,
num_rand = (unsigned long) RAND_MAX + 1,
bin_size = num_rand / num_bins,
defect = num_rand % num_bins;
long x;
do {
x = random();
}
// This is carefully written not to overflow
while (num_rand - defect <= (unsigned long)x);
// Truncated division is intentional
return x/bin_size;
}
La boucle est nécessaire pour obtenir une distribution parfaitement uniforme. Par exemple, si vous recevez des nombres aléatoires de 0 à 2 et que vous ne voulez que des nombres de 0 à 1, vous continuez à tirer jusqu'à ce que vous n'obteniez pas un 2; il n'est pas difficile de vérifier que cela donne 0 ou 1 avec une probabilité égale. Cette méthode est également décrite dans le lien que nos a donné dans leur réponse, bien que codée différemment. J'utilise random()
plutôt que rand()
car il a une meilleure distribution (comme indiqué par la page de manuel pour rand()
).
Si vous souhaitez obtenir des valeurs aléatoires en dehors de la plage par défaut [0, RAND_MAX]
, vous devez faire quelque chose de délicat. Le plus opportun est peut-être de définir une fonction random_extended()
qui extrait les n
bits (en utilisant random_at_most()
) et les retourne [0, 2**n)
, puis appliquez random_at_most()
avec random_extended()
à la place de random()
(et 2**n - 1
à la place de RAND_MAX
) pour extraire une valeur aléatoire inférieure à 2**n
, en supposant que vous avez un type numérique qui peut contenir un tel une valeur. Enfin, bien sûr, vous pouvez obtenir des valeurs en [min, max]
utilisant min + random_at_most(max - min)
, y compris des valeurs négatives.