Tutte le risposte finora sono matematicamente sbagliate. La restituzione rand() % N
non fornisce in modo uniforme un numero nell'intervallo a [0, N)
meno che non N
divida la lunghezza dell'intervallo in cui rand()
restituisce (cioè è una potenza di 2). Inoltre, non si sa se i moduli di rand()
siano indipendenti: è possibile che vadano 0, 1, 2, ...
, il che è uniforme ma non molto casuale. L'unica ipotesi che sembra ragionevole formulare è che rand()
emetta una distribuzione di Poisson: qualsiasi due sottointervalli non sovrapposti della stessa dimensione sono ugualmente probabili e indipendenti. Per un insieme finito di valori, ciò implica una distribuzione uniforme e garantisce anche che i valori di rand()
siano ben distribuiti.
Ciò significa che l'unico modo corretto per modificare l'intervallo di rand()
è dividerlo in caselle; ad esempio, se RAND_MAX == 11
desideri un intervallo di 1..6
, devi assegnarlo {0,1}
a 1,{2,3}
a 2 e così via. Questi sono intervalli disgiunti, di uguali dimensioni e quindi sono distribuiti in modo uniforme e indipendente.
Il suggerimento di utilizzare la divisione in virgola mobile è matematicamente plausibile, ma in linea di principio soffre di problemi di arrotondamento. Forsedouble
è una precisione abbastanza alta per farlo funzionare; forse no. Non lo so e non voglio doverlo capire; in ogni caso, la risposta dipende dal sistema.
Il modo corretto è usare l'aritmetica dei numeri interi. Cioè, vuoi qualcosa di simile al seguente:
#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;
}
Il loop è necessario per ottenere una distribuzione perfettamente uniforme. Ad esempio, se ti vengono dati numeri casuali da 0 a 2 e vuoi solo quelli da 0 a 1, continua a tirare finché non ottieni un 2; non è difficile controllare che questo dia 0 o 1 con uguale probabilità. Questo metodo è descritto anche nel link che i nn hanno dato nella loro risposta, sebbene codificato in modo diverso. Sto usando random()
piuttosto che rand()
in quanto ha una distribuzione migliore (come notato dalla pagina man per rand()
).
Se vuoi ottenere valori casuali al di fuori dell'intervallo predefinito [0, RAND_MAX]
, devi fare qualcosa di complicato. Forse il più opportuno è definire una funzione random_extended()
che tira n
bit (usando random_at_most()
) e ritorna dentro [0, 2**n)
, quindi applicare random_at_most()
con random_extended()
al posto di random()
(e 2**n - 1
al posto di RAND_MAX
) per estrarre un valore casuale inferiore a 2**n
, supponendo che tu abbia un tipo numerico che può contenere tale un valore. Infine, ovviamente, puoi ottenere valori in [min, max]
uso min + random_at_most(max - min)
, inclusi valori negativi.