Random float-Zahl generation
Wie erstelle ich zufällige schwimmt in C++?
Dachte ich, ich könnte die ganze Zahl rand und teilen Sie es durch etwas, wäre das ausreichend genug?
- Es hängt vielmehr das, was Sie möchten, die Anzahl, und wie zufällig. in der Regel rand() geben 15 bits des Zufalls, aber die Schwimmer haben 23 bit Genauigkeit, also es fehlen einige Werte aus.
- Ich habe aktualisiert mein Antwort auf alle wichtigen Optionen und meine Entscheidung, den Fokus auf
random
- header Hinzugefügt, in C++11 wird weiter gestärkt durch das standard-Dokument N3924: Entmutigend rand() in C++14. Ichrand()
in meiner Antwort für die meist historischen überlegungen, sondern auch zu erkennen legacy-Anwendung existieren. - Meine Antwort enthält, wie Sie es vermeiden, die gleichen zahlen haben jedes mal die
<random>
header
Du musst angemeldet sein, um einen Kommentar abzugeben.
rand()
verwendet werden kann zum erzeugen von pseudo-Zufallszahlen in C++. In Kombination mitRAND_MAX
und ein wenig Mathematik, können Sie erzeugen zufällige zahlen in jedem beliebigen Intervall, das Sie wählen. Dies ist ausreichend für Lern-Zwecke und Spielzeug-Programme. Wenn Sie brauchen wirklich Zufallszahlen mit Normalverteilung, müssen Sie beschäftigen eine erweiterte Methode.Erzeugt dies eine Zahl von 0.0 bis 1.0, inklusive.
Dies erzeugt eine Reihe von 0.0 auf einer beliebigen
float
,X
:Erzeugt dies eine Zahl von einem beliebigen
LO
einige beliebigeHI
:Beachten Sie, dass die
rand()
Funktion wird oft nicht ausreichend sein, wenn Sie brauchen, wirklich zufällige zahlen.Bevor Sie
rand()
, müssen Sie zuerst die "Samen" der Zufallszahlengenerator durch Aufrufsrand()
. Sollte dies einmal während Ihres Programms ausgeführt-nicht einmal jedes mal, wenn Sie rufenrand()
. Dies wird oft durchgeführt wie diese:Fordern
rand
odersrand
müssen Sie#include <cstdlib>
.Fordern
time
müssen Sie#include <ctime>
.int
?double a = 0.0/0.0; int x = (int) a; printf("%i", x)
.NaN
in einemint
, wird Ihre random-Funktion werden Sie wieder einNaN
.<ctime>
statt.rand()
's: "eine derk/RAND_MAX
" (für die 1. code-Beispiel).static_cast
anstelle von C-Stil-casts? Natürlich es ist nicht nötig, aber IMO regt es zum guten Stil, für jede neue Programmierer Lesen dieser Antwort.static_cast
(z.B. Konvertierung) und B) wollte ich die Beispiele zu kurz.static_cast
rand()
. Diese Frage, und meine Antwort war speziell ausgerichtet auf das erlernen der Grundlagen und war nicht besorgt über den hohen Grad an Präzision. Sie haben laufen zu lernen, bevor Sie laufen lernen.C++11 gibt Ihnen eine Menge neuer Möglichkeiten mit
random
. Die kanonische Papier zu diesem Thema wäre N3551, Random Number Generation, die in C++11Sehen, warum mit
rand()
problematisch sein kann, siehe die rand() considered harmful Präsentation material von Stephan T. Lavavej, die Sie während der GoingNative 2013 Veranstaltung. Die Folien sind in den Kommentaren aber hier ist ein direkter link.Ich auch cover
boost
sowie mitrand
seit legacy-code benötigen noch Ihre Unterstützung.Beispiel unten ist destilliert aus dem cppreference Website und verwendet die std::mersenne_twister_engine Motor und die std::uniform_real_distribution generiert zahlen in der
[0,10)
Intervall, mit anderen Motoren und Distributionen auskommentiert (sehen Sie es live):Ausgabe ähnlich der folgenden:
Die Ausgabe variieren je nachdem, welche distribution Sie wählen, so dass, wenn wir beschlossen zu gehen mit std::normal_distribution mit einem Wert von
2
für beide bedeuten und stddev z.B.dist(2, 2)
stattdessen die Ausgabe ähnlich wie diese (sehen Sie es live):Folgende ist eine modifizierte version von einigen der dargestellten code in
N3551
(sehen Sie es live) :Ergebnisse ähnlich sieht:
Boost
Natürlich Boost.Random ist immer eine option, hier bin ich mit boost::random::uniform_real_distribution:
rand()
Wenn Sie verwenden müssen
rand()
dann können wir gehen, um die C FAQ für einen Führer auf Wie kann ich generieren Fließkomma-Zufallszahlen? , die im Grunde gibt ein Beispiel, ähnlich wie dies für die Erzeugung einer auf das Intervall[0,1)
:und zum generieren einer zufälligen Zahl im Bereich von
[M,N)
:randMToN
pls? entweder beachten Sie, dass es[M,N]
oder wieder hinzufügen der+ 1.
aus den obenrandZeroToOne
. -> denken Sie nennen es so:randMToN(0.0, 1.0);
(N-M)
. Ein schöner Weg, um diesen Fehler zu beheben, ist hier zu finden: stackoverflow.com/questions/33058848/...Werfen Sie einen Blick auf Boost.Random. Sie könnte so etwas tun:
Spielen, um Sie vielleicht besser tun, übergeben die gleichen mt19937 Objekt um statt der Errichtung einer neuen jedes mal, aber hoffentlich bekommen Sie die Idee.
max
aber kann verwenden Sie einen open-endedmin
, können Sie rückgängig machen, das Intervall einfach:return min + max - gen();
.Rufen Sie den code mit zwei
float
Werte, der code funktioniert in jedem Bereich.fmaf()
(oder floatfma()
overload in C++) in C99 und C++11, die erhalten könnte mehr Präzision. Wie infmaf((float)rand() / RAND_MAX, b - a, a)
.Wenn Sie C++ und nicht C, dann denken Sie daran, dass im technical report 1 (TR1) und in der C++0x draft haben Sie zusätzliche Einrichtungen für einen Zufallszahlengenerator in der header-Datei, ich glaube es ist identisch mit dem Boost.Random-Bibliothek und auf jeden Fall flexibler und "moderner" als der C-library-Funktion, rand.
Diese syntax bietet die Möglichkeit, einen generator (wie der mersenne twister mt19937) und wählen Sie dann eine Verteilung (normal -, bernoulli -, binomial -, etc.).
Syntax ist wie folgt (schamlos ausgeliehen von diese Website):
In der modernen
c++
können Sie die<random>
header, der kam mitc++11
.Für zufällige
float
's, die Sie verwenden könnenstd::uniform_real_distribution<>
.Können Sie eine Funktion zum generieren von zahlen, und wenn Sie nicht wollen, dass die zahlen die gleichen die ganze Zeit, stellen Sie den Motor und Verteilung
static
.Beispiel:
Es ist ideal, um den Ort der
float
's in einem container wiestd::vector
:Beispiel-Ausgabe:
Auf manchen Systemen (Windows mit VC Federn in den Sinn, derzeit),
RAND_MAX
ist lächerlich klein, ich. e. nur 15 bit. Bei der Division durchRAND_MAX
Sie generieren nur eine Mantisse von 15 bit statt der 23 möglichen bits. Dies kann oder kann nicht ein problem für Sie, aber Sie verpassen einige Werte in diesem Fall.Oh, gerade bemerkt, dass es bereits einen Kommentar zu diesem problem. Wie auch immer, hier ist etwas code, der möglicherweise lösen das für Sie:
Ungetestet, könnte aber funktionieren 🙂
drand48(3)
ist die POSIX-standard-Weg. GLibC stellt auch eine ablaufinvariante version,drand48_r(3)
.Wurde die Funktion als veraltet erklärt in SVID 3, aber keine adäquate alternative zur Verfügung gestellt, so IEEE Std 1003.1-2013 noch schließt es und hat keine Hinweise, dass es überall jederzeit schnell.
In Windows ist der standard-Weg ist CryptGenRandom().
Ich nicht zufrieden war, indem einer der Antworten, so weit, so schrieb ich ein neues random-float-Funktion. Es macht bitweise Annahmen über den Datentyp float. Es muss noch ein rand () - Funktion mit mindestens 15 zufälligen bits.
Meiner Meinung nach die obige Antwort geben einige 'zufällig' schwimmen, aber keiner von Ihnen ist wirklich ein random float (d.h. Sie verpassen einen Teil der float-Darstellung). Bevor ich die Hektik in meiner Implementierung können zunächst einen Blick auf die ANSI/IEEE-standard-format für Fließkommazahlen:
|sign (1-bit)| e (8-bit) | f (23 bit) |
die Anzahl vertreten durch das Wort " ist
(-1 * sign) * 2^e * 1.f
beachten Sie die " e " - Nummer ist voreingestellt (mit einem bias von 127) Anzahl so reicht von -127 bis 126. Der einfachste (und eigentlich die meisten random) Funktion ist, schreiben Sie einfach die Daten von einem random-int in ein float, so
beachten Sie, dass wenn Sie
float f = (float)rand();
wird es konvertiert den integer in einen float (also 10 werden 10.0).So jetzt, wenn Sie wollen, um die maximal-Wert kannst du so etwas tun (nicht sicher, ob dies funktioniert)
aber wenn man sich die Struktur der float-Sie können sehen, dass der maximale Wert eines float ist (ca) 2^127 die Art und Weise, die größer als der maximale Wert eines int (2^32) somit ausschließt, ein erheblicher Teil der zahlen, die dargestellt werden kann durch einen Schwimmer.
Dies ist meine Letzte Umsetzung:
mithilfe dieser Funktion
randf(0, 8, 0)
liefert eine Zufallszahl zwischen 0.0 und 255.0int e = (rand() % (max_exp - min_exp)) + min_exp_mod;
und der Mantisse:int f = (int)(frac_mod * (float)rand() / RAND_MAX);
ersetzen die entsprechenden Zeilen vor. Beachten Sie, dass die Mantisse Fehler-Dur: fürRAND_MAX
kleinere1 << 23
würde man nur randomise die unteren bits und bekommen 0s für die wichtigsten bits, die ganze Zeit!Wenn Sie wissen, dass Ihre floating-point-format ist IEEE 754 (fast alle modernen CPUs, einschließlich Intel-und ARM -) dann können Sie erstellen eine zufällige Gleitkomma-Zahl aus eine zufällige ganze Zahl mit bit-weiser Methoden. Dies sollte nur berücksichtigt werden, wenn Sie keinen Zugang zu C++11 ist
random
oderBoost.Random
, die sind beide viel besser.Diese geben eine bessere Verteilung als eine mittels division.
return (float)random23 / (1 << 23)
. (Ja, ich habe gerade getestet, Sie ändern Ihre Funktion zu nehmenrandom32
als parameter und es läuft für alle Werte von null bis zu(1 << 23)-1
. Und ja, deine Methode funktioniert in der Tat genau die gleichen Ergebnisse wie die division durch1 << 23
.)Für C++, die es erzeugen kann, die real float-zahlen innerhalb des angegebenen Bereichs von
dist
variablerand() return int zwischen 0 und RAND_MAX. Um eine zufällige Zahl zwischen 0.0 und 1.0, der erste cast den int-return von rand() eine float Division durch RAND_MAX.
Konnte ich nicht post zwei Antworten, also hier ist die zweite Lösung. log2 Zufallszahlen, massive bias in Richtung 0.0 f, aber es ist wirklich ein random float 1.0 f, 0.0 f.