Wie erhalte ich einen bestimmten Zahlenbereich von rand()?

Lesezeit: 9 Minuten

Benutzeravatar von akway
okay

srand(time(null));

printf("%d", rand());

Gibt eine High-Range-Zufallszahl (0-32000ish), aber ich brauche nur etwa 0-63 oder 0-127, obwohl ich nicht sicher bin, wie ich vorgehen soll. Irgendeine Hilfe?

  • Zwei Dinge, die Sie hier beachten sollten: 1. Entfernen Sie niemals die höheren Bits, da die niedrigeren oft weniger zufällig sind. 2. Verwenden Sie niemals das vom System bereitgestellte rand(), es sei denn, Sie brauchen nicht wirklich gute Zufallszahlen.

    – David Thornley

    29. Juli 2009 um 20:18 Uhr

  • Ich werde später ein besseres RNG verwenden, im Moment spiele ich nur damit herum, zufällige Bilder zu generieren.

    – ok

    29. Juli 2009 um 20:22 Uhr

  • @David: Sie müssen sich nicht an diese beiden Dinge erinnern, nur an das Zweite. Wenn Sie nie rand() verwenden, müssen Sie sich keine Gedanken darüber machen, welche Bits in typischen Implementierungen beschissen sind. Wenn Sie einen guten RNG verwenden, sind die niedrigen Bits genauso gut wie die hohen.

    – Steve Jessop

    29. Juli 2009 um 23:06 Uhr

  • Verwandte: Wie generiert man ein zufälliges int in C?. Hier ist meine Antwort dort, die die Definition für my enthält int utils_rand(int min, int max) func, die eine Zufallszahl mit zurückgibt rand() das liegt im konkreten Bereich aus min zu max, inklusive, und beantwortet damit auch diese Frage. Ich skaliere auch, um einen Fall zuzulassen, in dem min ist INT_MIN und max ist INT_MAXwas normalerweise nicht möglich ist rand() allein, da es Werte von zurückgibt 0 zu RAND_MAXeinschließlich (1/2 dieses Bereichs).

    – Gabriel Staples

    31. Mai 2021 um 21:01 Uhr


Benutzeravatar von Tyler McHenry
Tyler McHenry

rand() % (max_number + 1 - minimum_number) + minimum_number

Also für 0-65:

rand() % (65 + 1 - 0) + 0

(Natürlich können Sie die 0 weglassen, aber sie dient der Vollständigkeit).

Beachten Sie, dass dies die Zufälligkeit leicht beeinflusst, aber wahrscheinlich nichts, worüber Sie sich Sorgen machen müssten, wenn Sie nicht etwas besonders Sensibles tun.

  • nein, es ist immer noch number_of_numbers, aber die Anzahl der Zahlen im inklusiven Bereich 0-65 ist 66 und nicht 65.

    – Tyler McHenry

    29. Juli 2009 um 20:09 Uhr

  • Ich glaube, das hat “rand() % 65 + 0” gesagt, als ich meinen Kommentar gepostet habe. Es sieht jetzt so aus.

    – Fred Larson

    29. Juli 2009 um 20:12 Uhr

  • Das hat es gesagt. Ich meinte, dass ich mich bei der Nummer geirrt habe, die ich in das zweite Code-Snippet geschrieben habe, aber nicht bei dem Namen, den ich der Variablen im ersten Code-Snippet gegeben habe.

    – Tyler McHenry

    29. Juli 2009 um 20:14 Uhr

  • Modulo stützt sich auf die niederwertigen Bits, die nicht so zufällig sind wie die höherwertigen Bits. In Float umwandeln und multiplizieren funktioniert besser.

    – S. Lott

    29. Juli 2009 um 20:17 Uhr

  • Die niederwertigen Bits SIND weniger zufällig. Je kleiner der Wert von ist number_of_numbers, desto offensichtlicher ist die Voreingenommenheit. Hat nichts mit RAND_MAX zu tun. Wenn number_of_numbers 2 ist, sehen Sie die Abweichung im niederwertigsten Bit.

    – S. Lott

    30. Juli 2009 um 12:07 Uhr

überprüfe hier

http://c-faq.com/lib/randrange.html

Für jede dieser Techniken ist es einfach, den Bereich bei Bedarf zu verschieben; Nummern im Bereich [M, N] könnte mit so etwas wie generiert werden

M + rand() / (RAND_MAX / (N - M + 1) + 1)

  • Sie möchten, dass eine dieser 1s 1,0 ist, um einen Float zu gewährleisten, andernfalls erhalten Sie nur 0 + M …

    – Brian Postow

    29. Juli 2009 um 20:42 Uhr

  • @BrianPostow Nein, das tust du definitiv nicht wollen dort eine Fließkommazahl. Die Rechnung ist korrekt, so wie sie da steht und Zufallszahlen dazwischen produziert M und N (inklusive). Die Verteilung ist recht gleichmäßig, solange N-M ist klein im Vergleich zu RAND_MAX. Lesen Sie den verlinkten Artikel.

    – Fritz

    17. Juni 2016 um 14:13 Uhr


  • Habe ich meine Implementierung vermasselt? Scheint sehr schlecht für meine zugegebenermaßen kleinen Testfälle zu sein (implementiert in thirdRange()). repl.it/@altendky/scaling-rand-can-cause-poor-distribution Hat es in den begrenzten Fällen einen Wert gegenüber der am besten bewerteten Antwort? N-M klein im Vergleich zu RAND_MAX?

    – alterdky

    22. Januar 2018 um 22:51 Uhr

Benutzeravatar von Vitim.us
Vitim.us

Sie können dies verwenden:

int random(int min, int max){
   return min + rand() / (RAND_MAX / (max - min + 1) + 1);
}

Von dem:

comp.lang.c FAQ-Liste · Frage 13.16

F: Wie kann ich zufällige Ganzzahlen in einem bestimmten Bereich erhalten?

A: Der offensichtliche Weg,

rand() % N        /* POOR */

(der versucht, Zahlen von 0 bis N-1 zurückzugeben) ist schlecht, weil die niederwertigen Bits vieler Zufallszahlengeneratoren erschreckenderweise nicht zufällig sind. (Siehe Frage 13.18.) Eine bessere Methode ist so etwas wie

(int)((double)rand() / ((double)RAND_MAX + 1) * N)

Wenn Sie lieber kein Fließkomma verwenden möchten, ist eine andere Methode

rand() / (RAND_MAX / N + 1)

Wenn Sie nur etwas mit Wahrscheinlichkeit 1/N tun müssen, könnten Sie verwenden

if(rand() < (RAND_MAX+1u) / N)

All diese Methoden erfordern offensichtlich die Kenntnis von RAND_MAX (das ANSI # in definiert) und nehmen an, dass N viel kleiner als RAND_MAX ist. Wenn N in der Nähe von RAND_MAX liegt und der Bereich des Zufallszahlengenerators kein Vielfaches von N ist (dh wenn (RAND_MAX+1) % N != 0), brechen alle diese Methoden zusammen: Einige Ausgaben treten häufiger als auf Andere. (Die Verwendung von Gleitkommazahlen hilft nicht; das Problem besteht darin, dass rand RAND_MAX+1 unterschiedliche Werte zurückgibt, die nicht immer gleichmäßig in N Buckets aufgeteilt werden können.) Wenn dies ein Problem darstellt, können Sie rand als Vielfaches aufrufen Zeiten, wobei bestimmte Werte verworfen werden:

unsigned int x = (RAND_MAX + 1u) / N;
unsigned int y = x * N;
unsigned int r;
do {
  r = rand();
} while(r >= y);
return r / x;

Für jede dieser Techniken ist es einfach, den Bereich bei Bedarf zu verschieben; Nummern im Bereich [M, N] könnte mit so etwas wie generiert werden

M + rand() / (RAND_MAX / (N - M + 1) + 1)

(Beachten Sie übrigens, dass RAND_MAX ein ist Konstante Ihnen sagen, was der feste Bereich der C-Bibliothek ist Rand Funktion ist. Sie können RAND_MAX nicht auf einen anderen Wert setzen, und es gibt keine Möglichkeit, dies anzufordern Rand
Zahlen in einem anderen Bereich zurückgeben.)

Wenn Sie mit einem Zufallszahlengenerator beginnen, der Gleitkommawerte zwischen 0 und 1 zurückgibt (wie die letzte Version von
PMrand fraglich angedeutet 13.15oder drand48 in Frage
13.21), alles, was Sie tun müssen, um ganze Zahlen von 0 bis N-1 zu erhalten, ist, die Ausgabe dieses Generators mit N zu multiplizieren:

(int)(drand48() * N)

Zusätzliche Links

Referenzen: K&R2 Sek. 7.8.7 p. 168
PCS-Sek. 11 p. 172

Zitat aus: http://c-faq.com/lib/randrange.html

Benutzeravatar von Bob Kaufman
Bob Kaufmann

Wenn Sie den Modulo des Ergebnisses nehmen, wie die anderen Poster behauptet haben, erhalten Sie etwas, das ist fast zufällig, aber nicht perfekt.

Betrachten Sie dieses extreme Beispiel, nehmen Sie an, Sie wollten einen Münzwurf simulieren und entweder 0 oder 1 zurückgeben. Sie könnten dies tun:

isHeads = ( rand() % 2 ) == 1;

Sieht harmlos aus, oder? Angenommen, RAND_MAX ist nur 3. Es ist natürlich viel höher, aber der Punkt hier ist, dass es eine Verzerrung gibt, wenn Sie einen Modul verwenden, der RAND_MAX nicht gleichmäßig teilt. Wenn Sie qualitativ hochwertige Zufallszahlen wollen, werden Sie ein Problem haben.

Betrachten Sie mein Beispiel. Die möglichen Ergebnisse sind:

rand()  freq. rand() % 2
0       1/3   0
1       1/3   1
2       1/3   0

Daher kommt “Zahl” doppelt so oft vor wie “Kopf”!

Herr Atwood bespricht diese Angelegenheit in diesem Coding-Horror-Artikel

Benutzeravatar von Michael Myers
Michael myers

Der naive Weg, es zu tun, ist:

int myRand = rand() % 66; // for 0-65

Dies wird wahrscheinlich eine sehr leicht ungleichmäßige Verteilung sein (abhängig von Ihrem Maximalwert), aber es ist ziemlich nah dran.

Um zu erklären, warum es nicht ganz einheitlich ist, betrachten Sie dieses sehr vereinfachte Beispiel:
Angenommen, RAND_MAX ist 4 und Sie möchten eine Zahl von 0 bis 2. Die möglichen Werte, die Sie erhalten können, sind in dieser Tabelle aufgeführt:

rand()   |  rand() % 3
---------+------------
0        |  0
1        |  1
2        |  2
3        |  0

Sehen Sie das Problem? Wenn Ihr Maximalwert kein gerader Teiler von RAND_MAX ist, wählen Sie eher kleine Werte. Da RAND_MAX jedoch im Allgemeinen 32767 beträgt, ist die Abweichung wahrscheinlich klein genug, um für die meisten Zwecke davonzukommen.

Es gibt verschiedene Möglichkeiten, dieses Problem zu umgehen; sehen hier für eine Erklärung, wie Java’s Random handhabt es.

  • Ich habe es bearbeitet zweimal in der Zeit, die ihr gebraucht habt, um Kommentare zu hinterlassen. 😉

    – Michael myers

    29. Juli 2009 um 20:05 Uhr

  • @akway – es ist auf niedrige Werte ausgerichtet. Je nach Reichweite kann es sehr schief sein. Einzelheiten zu Alternativen finden Sie in dem Artikel, auf den ich in meiner Antwort verweise.

    – Reed Copsey

    29. Juli 2009 um 20:11 Uhr

  • Aus Ihren Beispielen sieht es so aus, als könnte ich einfach alle Ergebnisse verwerfen, die auf 0 enden, und ich wäre in Ordnung … oder irre ich mich?

    – ok

    29. Juli 2009 um 20:16 Uhr

  • @akway: Was passiert, wenn RAND_MAX im Beispiel 5 ist?

    – Michael myers

    29. Juli 2009 um 20:20 Uhr

  • 3->3, 4->0? Ich bin mir nicht sicher, ehrlich zu sein.

    – ok

    29. Juli 2009 um 20:34 Uhr

Joeys Benutzeravatar
Joey

Wie andere angemerkt haben, wird die einfache Verwendung eines Moduls die Wahrscheinlichkeiten für einzelne Zahlen verzerren, sodass kleinere Zahlen bevorzugt werden.

Eine sehr geniale und gute Lösung für dieses Problem wird in Java verwendet java.util.Random Klasse:

public int nextInt(int n) {
    if (n <= 0)
        throw new IllegalArgumentException("n must be positive");

    if ((n & -n) == n)  // i.e., n is a power of 2
        return (int)((n * (long)next(31)) >> 31);

    int bits, val;
    do {
        bits = next(31);
        val = bits % n;
    } while (bits - val + (n-1) < 0);
    return val;
}

Ich habe eine Weile gebraucht, um zu verstehen, warum es funktioniert, und ich überlasse das dem Leser als Übung, aber es ist eine ziemlich prägnante Lösung, die sicherstellt, dass Zahlen gleiche Wahrscheinlichkeiten haben.

Der wichtige Teil in diesem Codestück ist die Bedingung für die while -Schleife, die Zahlen zurückweist, die in den Zahlenbereich fallen, der sonst zu einer ungleichmäßigen Verteilung führen würde.

  • Ich habe es bearbeitet zweimal in der Zeit, die ihr gebraucht habt, um Kommentare zu hinterlassen. 😉

    – Michael myers

    29. Juli 2009 um 20:05 Uhr

  • @akway – es ist auf niedrige Werte ausgerichtet. Je nach Reichweite kann es sehr schief sein. Einzelheiten zu Alternativen finden Sie in dem Artikel, auf den ich in meiner Antwort verweise.

    – Reed Copsey

    29. Juli 2009 um 20:11 Uhr

  • Aus Ihren Beispielen sieht es so aus, als könnte ich einfach alle Ergebnisse verwerfen, die auf 0 enden, und ich wäre in Ordnung … oder irre ich mich?

    – ok

    29. Juli 2009 um 20:16 Uhr

  • @akway: Was passiert, wenn RAND_MAX im Beispiel 5 ist?

    – Michael myers

    29. Juli 2009 um 20:20 Uhr

  • 3->3, 4->0? Ich bin mir nicht sicher, ehrlich zu sein.

    – ok

    29. Juli 2009 um 20:34 Uhr

rand() gibt Zahlen zwischen 0 und RAND_MAX zurück, was mindestens 32767 ist.

Wenn Sie eine Zahl innerhalb eines Bereichs erhalten möchten, können Sie einfach Modulo verwenden.

int value = rand() % 66; // 0-65

Für mehr Genauigkeit, Schauen Sie sich diesen Artikel an. Es erläutert, warum Modulo nicht unbedingt gut ist (schlechte Distributionen, insbesondere im High-End-Bereich), und bietet verschiedene Optionen.

1416430cookie-checkWie erhalte ich einen bestimmten Zahlenbereich von rand()?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy