Toutes les réponses sont mathématiquement faux. De retour rand() % N
n'est pas uniformément donner un nombre dans l'intervalle [0, N)
moins N
divise la longueur de l'intervalle dans lequel rand()
retours (c'est à dire une puissance de 2). En outre, on n'a aucune idée de savoir si les modules d' rand()
sont indépendants: il est possible qu'ils vont 0, 1, 2, ...
, ce qui est uniforme, mais pas très aléatoire. La seule hypothèse, il semble raisonnable de faire est qu' rand()
met une distribution de Poisson: tous les deux ne se chevauchent pas les sous-intervalles de même taille sont équiprobables et indépendants. Pour un ensemble fini de valeurs, ce qui implique une distribution uniforme et s'assure également que les valeurs de rand()
sont bien dispersés.
Cela signifie que la seule façon correcte de l'évolution de la gamme de rand()
est de le diviser en boîtes; par exemple, si RAND_MAX == 11
et que vous voulez une gamme d' 1..6
, vous devez attribuer {0,1}
1, {2,3}
à 2, et ainsi de suite. Ce sont disjoints, de même taille intervalles et sont donc uniformément et indépendamment distribués.
La proposition de recourir à la division flottante est mathématiquement plausible, mais souffre de arrondissement des questions de principe. Peut - double
est élevé suffisamment de précision pour le faire fonctionner; peut-être pas. Je ne sais pas et je ne veux pas le comprendre; en tout cas, la réponse est dépendant du système.
La bonne façon est d'utiliser l'arithmétique des nombres entiers. Qui est, vous voulez quelque chose comme ce qui suit:
#include <stdlib.h> // For random(), RAND_MAX
// Assumes 0 <= range <= RAND_MAX
// Returns in the half-open 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 % bin_size;
long x;
// This is carefully written not to overflow
while (num_rand - defect <= (unsigned long)(x = random()));
// Truncated division is intentional
return x/bin_size;
}
La boucle est nécessaire pour obtenir une parfaite uniformité de la distribution. Par exemple, si vous êtes donné des nombres aléatoires de 0 à 2 et que vous voulez seulement ceux de 0 à 1, vous continuez à tirer jusqu'à ce que vous n'obtenez 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 la nsa a donné dans leur réponse, bien codé différemment. Je suis à l'aide d' random()
plutôt que d' rand()
comme il a une meilleure distribution (comme l'a noté la page de man pour rand()
).
Si vous souhaitez obtenir des valeurs aléatoires à l'extérieur de la plage par défaut [0, RAND_MAX]
, alors vous devez faire quelque chose de délicat. Peut-être le moyen le plus efficace est de définir une fonction random_extended()
qui tire n
bits (à l'aide d' random_at_most()
) et des rendements en [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 tirer une valeur aléatoire à moins de 2**n
, en supposant que vous avez un type numérique qui peut contenir une valeur de ce type. Enfin, bien sûr, vous pouvez obtenir les valeurs en [min, max]
l'aide min + random_at_most(max - min + 1)
, y compris les valeurs négatives.