Alle bisherigen Antworten sind mathematisch falsch. Die Rückgabe rand() % N
gibt nicht einheitlich eine Zahl im Bereich an, es [0, N)
sei denn, N
die Länge des Intervalls, in das die rand()
Rückgabe erfolgt (dh eine Potenz von 2). Außerdem hat man keine Ahnung, ob die Module von rand()
unabhängig sind: Es ist möglich, dass sie gehen 0, 1, 2, ...
, was einheitlich, aber nicht sehr zufällig ist. Die einzige Annahme, die vernünftig erscheint, ist die, dass rand()
eine Poisson-Verteilung ausgegeben wird: Zwei beliebige nicht überlappende Teilintervalle derselben Größe sind gleich wahrscheinlich und unabhängig. Für eine endliche Menge von Werten impliziert dies eine gleichmäßige Verteilung und stellt auch sicher, dass die Werte von rand()
gut verteilt sind.
Dies bedeutet, dass der einzig richtige Weg, den Bereich von rand()
zu ändern, darin besteht, ihn in Kästchen zu unterteilen. Wenn RAND_MAX == 11
Sie beispielsweise einen Bereich von möchten 1..6
, sollten Sie {0,1}
1, {2,3}
2 usw. zuweisen . Dies sind disjunkte, gleich große Intervalle und somit gleichmäßig und unabhängig verteilt.
Der Vorschlag, eine Gleitkommadivision zu verwenden, ist mathematisch plausibel, weist jedoch im Prinzip Rundungsprobleme auf. Vielleicht double
ist die Präzision hoch genug, damit es funktioniert. vielleicht nicht. Ich weiß es nicht und ich möchte es nicht herausfinden müssen; In jedem Fall ist die Antwort systemabhängig.
Der richtige Weg ist die Verwendung von Ganzzahlarithmetik. Das heißt, Sie möchten so etwas wie das Folgende:
#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;
}
Die Schleife ist notwendig, um eine perfekt gleichmäßige Verteilung zu erhalten. Wenn Sie beispielsweise Zufallszahlen von 0 bis 2 erhalten und nur solche von 0 bis 1 möchten, ziehen Sie einfach weiter, bis Sie keine 2 mehr erhalten. Es ist nicht schwer zu überprüfen, ob dies mit gleicher Wahrscheinlichkeit 0 oder 1 ergibt. Diese Methode wird auch in dem Link beschrieben, den nos in ihrer Antwort angegeben haben, obwohl sie unterschiedlich codiert sind. Ich verwende random()
eher als rand()
weil es eine bessere Verteilung hat (wie auf der Manpage für angegeben rand()
).
Wenn Sie zufällige Werte außerhalb des Standardbereichs erhalten möchten, [0, RAND_MAX]
müssen Sie etwas Schwieriges tun. Vielleicht ist die zweckmäßigste ist eine Funktion zu definieren , random_extended()
die zieht n
Bits (mit random_at_most()
) und kehrt in [0, 2**n)
, und wenden Sie dann random_at_most()
mit random_extended()
anstelle von random()
(und 2**n - 1
anstelle von RAND_MAX
als) zu ziehen , um einen zufälligen Wert weniger 2**n
, vorausgesetzt , Sie einen numerischen Typen haben, so halten kann , ein Wert. Schließlich, natürlich können Sie Werte erhalten in [min, max]
Verwendung min + random_at_most(max - min)
, einschließlich negativer Werte.