Wie generiere ich zufällige Floats in C ++?
Ich dachte, ich könnte den ganzzahligen Rand nehmen und ihn durch etwas teilen. Wäre das ausreichend?
c++
random
floating-point
hasen
quelle
quelle
random
die in C ++ 11 hinzugefügten Header zu konzentrieren, wird durch das Standarddokument N3924: Discouraging rand () in C ++ 14 weiter gestärkt . Ich bezieherand()
in meine Antwort hauptsächlich historische Überlegungen ein, aber auch die Realisierung einer Legacy-Anwendung.<random>
Header zu bekommenAntworten:
rand()
kann verwendet werden, um Pseudozufallszahlen in C ++ zu generieren. In Kombination mitRAND_MAX
und ein wenig Mathematik können Sie Zufallszahlen in einem beliebigen Intervall generieren. Dies reicht für Lernzwecke und Spielzeugprogramme aus. Wenn Sie wirklich zufällige Zahlen mit normaler Verteilung benötigen, müssen Sie eine fortgeschrittenere Methode anwenden.Dadurch wird eine Zahl von 0,0 bis einschließlich 1,0 generiert.
Dies wird eine Zahl von 0,0 bis zu einem gewissen willkürlichen erzeugen
float
,X
:Dies erzeugt eine Zahl von willkürlich
LO
zu willkürlichHI
:Beachten Sie, dass die
rand()
Funktion oft nicht ausreicht, wenn Sie wirklich zufällige Zahlen benötigen.Bevor Sie anrufen
rand()
, müssen Sie zuerst den Zufallszahlengenerator durch Aufrufen "setzen"srand()
. Dies sollte einmal während der Ausführung Ihres Programms erfolgen - nicht einmal bei jedem Aufrufrand()
. Dies geschieht oft so:Um anzurufen
rand
odersrand
müssen Sie#include <cstdlib>
.Um anzurufen
time
, müssen Sie#include <ctime>
.quelle
rand()
. Diese Frage und meine Antwort konzentrierten sich speziell auf das Erlernen der Grundlagen und waren nicht besorgt über ein hohes Maß an Präzision. Sie müssen laufen lernen, bevor Sie laufen lernen können.C ++ 11 bietet Ihnen viele neue Optionen mit
random
. Das kanonische Papier zu diesem Thema wäre N3551, Random Number Generation in C ++ 11Um zu sehen, warum die Verwendung
rand()
problematisch sein kann, lesen Sie das Rand () als schädliches Präsentationsmaterial von Stephan T. Lavavej, das während der GoingNative 2013- Veranstaltung gegeben wurde. Die Folien sind in den Kommentaren, aber hier ist ein direkter Link .Ich gehe
boost
auch auf die Verwendung ein,rand
da Legacy-Code möglicherweise noch Unterstützung benötigt.Das folgende Beispiel wurde von der cppreference-Site destilliert und verwendet die std :: mersenne_twister_engine- Engine und die std :: uniform_real_distribution, die im
[0,10)
Intervall Zahlen generiert , wobei andere Engines und Distributionen auskommentiert werden ( siehe live ):Die Ausgabe ähnelt der folgenden:
Der Ausgang wird variieren je nachdem , welche Distribution Sie wählen, so dass , wenn wir mit gehen entschieden std :: normal_distribution mit einem Wert von
2
sowohl mittleren und stddev zBdist(2, 2)
anstelle der Ausgang wäre ähnlich wie diesen ( siehe es leben ):Das Folgende ist eine modifizierte Version eines Teils des Codes, der in
N3551
( siehe live ) vorgestellt wird:Die Ergebnisse sehen ähnlich aus wie:
Boost
Natürlich ist Boost.Random auch immer eine Option, hier verwende ich boost :: random :: uniform_real_distribution :
rand ()
Wenn Sie verwenden müssen,
rand()
finden Sie in den C-FAQ eine Anleitung zum Wie kann ich Gleitkomma-Zufallszahlen generieren? , die im Grunde ein ähnliches Beispiel für die Erzeugung eines Intervalls gibt[0,1)
:und um eine Zufallszahl im Bereich von zu generieren
[M,N)
:quelle
randMToN
pls reparieren? Beachten Sie entweder, dass es ist,[M,N]
oder fügen Sie das+ 1.
von oben hinzurandZeroToOne
. -> denken Sie daran, es so zu nennen:randMToN(0.0, 1.0);
(N-M)
. Eine guteSchauen Sie sich Boost.Random an . Sie könnten so etwas tun:
Spielen Sie herum, vielleicht ist es besser, dasselbe mt19937-Objekt herumzugeben, als jedes Mal ein neues zu erstellen, aber hoffentlich haben Sie die Idee.
quelle
max
ein offenes Ende benötigen, aber verwenden könnenmin
, können Sie das Intervall einfach umkehren :return min + max - gen();
.In der Moderne können
c++
Sie den<random>
mitgelieferten Header verwendenc++11
.Um zufällige zu erhalten
float
, können Sie verwendenstd::uniform_real_distribution<>
.Sie können eine Funktion verwenden, um die Zahlen zu generieren. Wenn Sie nicht möchten, dass die Zahlen immer gleich sind , stellen Sie die Engine und die Verteilung so ein
static
.Beispiel:
Es ist ideal, die
float
in einen Behälter zu legen , wie zum Beispielstd::vector
:Beispielausgabe:
quelle
std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
ist technisch nicht korrekt, 1.0 wird niemals generiert, siehe en.cppreference.com/w/cpp/numeric/random/…To create a distribution over the closed interval [a,b], std::nextafter(b, std::numeric_limits<RealType>::max()) may be used as the second parameter.
Rufen Sie den Code mit zwei
float
Werten auf, der Code funktioniert in einem beliebigen Bereich.quelle
fmaf()
(oder die Float-fma()
Überladung in C ++) in C99 oder C ++ 11 ist, wodurch möglicherweise mehr Präzision erhalten bleibt. Wie in ,fmaf((float)rand() / RAND_MAX, b - a, a)
.Wenn Sie C ++ und nicht C verwenden, denken Sie daran, dass im technischen Bericht 1 (TR1) und im C ++ 0x-Entwurf Funktionen für einen Zufallszahlengenerator in der Header-Datei hinzugefügt wurden. Ich glaube, dass dieser mit dem Boost identisch ist. Zufällige Bibliothek und definitiv flexibler und "moderner" als die C-Bibliotheksfunktion, Rand.
Diese Syntax bietet die Möglichkeit, einen Generator (wie den Mersenne-Twister mt19937) und anschließend eine Verteilung (Normal, Bernoulli, Binomial usw.) auszuwählen.
Die Syntax lautet wie folgt (schamlos von dieser Site entlehnt ):
quelle
Auf einigen Systemen (Windows mit VC fällt derzeit ein)
RAND_MAX
ist lächerlich klein, d.h. e. nur 15 bit. WennRAND_MAX
Sie durch dividieren, erzeugen Sie nur eine Mantisse von 15 Bit anstelle der 23 möglichen Bits. Dies kann ein Problem für Sie sein oder auch nicht, aber in diesem Fall fehlen Ihnen einige Werte.Oh, habe gerade bemerkt, dass es bereits einen Kommentar zu diesem Problem gab. Wie auch immer, hier ist ein Code, der dies für Sie lösen könnte:
Ungetestet, könnte aber funktionieren :-)
quelle
drand48(3)
ist der POSIX-Standardweg. GLibC bietet auch eine wiedereintrittsfähige Versiondrand48_r(3)
.Die Funktion wurde in SVID 3 für veraltet erklärt, es wurde jedoch keine angemessene Alternative bereitgestellt, sodass IEEE Std 1003.1-2013 sie weiterhin enthält und keine Hinweise darauf enthält, dass sie bald irgendwohin geht.
In Windows ist CryptGenRandom () der Standard .
quelle
Bisher war ich mit keiner der Antworten zufrieden, daher habe ich eine neue zufällige Float-Funktion geschrieben. Es werden bitweise Annahmen über den Float-Datentyp getroffen. Es benötigt noch eine rand () - Funktion mit mindestens 15 zufälligen Bits.
quelle
Meiner Meinung nach gibt die obige Antwort einen 'zufälligen' Float, aber keiner von ihnen ist wirklich ein zufälliger Float (dh sie vermissen einen Teil der Float-Darstellung). Bevor ich mich mit meiner Implementierung befasse, werfen wir zunächst einen Blick auf das ANSI / IEEE-Standardformat für Floats:
| Vorzeichen (1 Bit) | e (8 Bit) | f (23 Bit) |
Die durch dieses Wort dargestellte Zahl ist (-1 * Vorzeichen) * 2 ^ e * 1.f.
Beachten Sie, dass die 'e'-Zahl eine voreingenommene (mit einer Vorspannung von 127) Zahl ist, die von -127 bis 126 reicht. Die einfachste (und tatsächlich zufälligste) Funktion besteht darin, nur die Daten eines zufälligen int in einen float zu schreiben. so
Beachten Sie,
float f = (float)rand();
dass in diesem Fall die Ganzzahl in einen Gleitkommawert umgewandelt wird (10 wird also zu 10,0).Wenn Sie nun den Maximalwert begrenzen möchten, können Sie Folgendes tun (nicht sicher, ob dies funktioniert).
Wenn Sie sich jedoch die Struktur des Floats ansehen, können Sie sehen, dass der Maximalwert eines Floats (ungefähr) 2 ^ 127 beträgt, was viel größer ist als der Maximalwert eines Int (2 ^ 32), wodurch ein wesentlicher Teil von ausgeschlossen wird die Zahlen, die durch einen Float dargestellt werden können. Dies ist meine endgültige Implementierung:
Bei Verwendung dieser Funktion
randf(0, 8, 0)
wird eine Zufallszahl zwischen 0,0 und 255,0 zurückgegebenquelle
int e = (rand() % (max_exp - min_exp)) + min_exp_mod;
und der Mantisse:int f = (int)(frac_mod * (float)rand() / RAND_MAX);
Ersetzen der jeweiligen Zeilen oben. Beachten Sie, dass der Mantissenfehler schwerwiegend ist: BeiRAND_MAX
kleineren1 << 23
Bits würden Sie nur die niedrigstwertigen Bits zufällig sortieren und die ganze Zeit 0s für die höchstwertigen Bits erhalten!Wenn Sie wissen, dass Ihr Gleitkommaformat IEEE 754 ist (fast alle modernen CPUs, einschließlich Intel und ARM), können Sie eine zufällige Gleitkommazahl aus einer zufälligen Ganzzahl mit bitweisen Methoden erstellen. Dies sollte nur berücksichtigt werden, wenn Sie keinen Zugriff auf C ++ 11 haben
random
oderBoost.Random
beide viel besser sind.Dies ergibt eine bessere Verteilung als eine mit Division.
quelle
return (float)random23 / (1 << 23)
. (Ja, ich habe dies gerade getestet , Ihre Funktion so geändert, dass sierandom32
als Parameter verwendet wird, und sie für alle Werte von Null bis ausgeführt(1 << 23)-1
. Und ja, Ihre Methode liefert tatsächlich genau die gleichen Ergebnisse wie die Division durch1 << 23
.)Für C ++ können echte Gleitkommazahlen innerhalb des durch die
dist
Variable angegebenen Bereichs generiert werdenquelle
rand () gibt ein int zwischen 0 und RAND_MAX zurück. Um eine Zufallszahl zwischen 0,0 und 1,0 zu erhalten, wandeln Sie zuerst die int-Rückgabe mit rand () in einen float um und dividieren Sie dann durch RAND_MAX.
quelle
Ich konnte keine zwei Antworten posten, daher hier die zweite Lösung. log2 Zufallszahlen, massive Tendenz zu 0.0f, aber es ist wirklich ein zufälliger Float 1.0f bis 0.0f.
quelle