Zufallszahlengenerierung in C ++ 11: Wie wird generiert, wie funktioniert es? [geschlossen]

102

Ich bin kürzlich auf eine neue Methode gestoßen, um Zufallszahlen in C ++ 11 zu generieren, konnte aber die Artikel , die ich darüber gelesen habe, nicht verarbeiten (was ist diese Engine , mathematischer Begriff wie Verteilung , "wo alle produzierten ganzen Zahlen gleich wahrscheinlich sind ").

Kann mir bitte jemand erklären

  • was sind Sie?
  • was bedeuten sie
  • wie generieren?
  • wie arbeiten Sie?
  • etc

Sie können alles in einer FAQ zur Zufallszahlengenerierung aufrufen.

informatik01
quelle
6
Nach RNGs zu fragen, ohne zu wissen, was eine Verteilung ist, ist wie nach Ausdrucksparsern zu fragen, ohne zu wissen, was ein Ausdruck ist ... Die RNG-Bibliothek in C ++ 11 richtet sich an Personen, die einige Statistiken kennen und größere Anforderungen haben als die von erzeugte flache Verteilung rand, sollten Sie einen kurzen Blick auf Wikipedia werfen, um einige grundlegende statistische und RNG-Konzepte zu finden. Andernfalls ist es sehr schwierig, Ihnen die Gründe <random>und die Verwendung der verschiedenen Teile zu erklären .
Matteo Italia
26
@ Matto: Kaum. Ein Kind kann das Konzept verstehen, dass ein Würfel Zufallszahlen erzeugt, ohne zu verstehen, was eine Verteilung ist.
Benjamin Lindley
3
@Benjamin: Und hier hört sein Verständnis auf, was nur der allererste Schritt (die Motoren) ist, und ohne zu verstehen, warum es wichtig ist, dass sie eine flache Verteilung erzeugen. Der gesamte Rest der Bibliothek bleibt ein Rätsel, ohne Verteilungen und andere statistische Konzepte zu verstehen.
Matteo Italia

Antworten:

142

Die Frage ist viel zu weit gefasst für eine vollständige Antwort, aber lassen Sie mich ein paar interessante Punkte herausgreifen:

Warum "gleich wahrscheinlich"

Angenommen, Sie haben einen einfachen Zufallszahlengenerator, der die Zahlen 0, 1, ..., 10 mit jeweils gleicher Wahrscheinlichkeit generiert (stellen Sie sich dies als Klassiker vor rand()). Jetzt möchten Sie eine Zufallszahl im Bereich 0, 1, 2 mit jeweils gleicher Wahrscheinlichkeit. Ihre Knie-Ruck-Reaktion wäre zu nehmen rand() % 3. Aber warten Sie, die Reste 0 und 1 kommen häufiger vor als die restlichen 2, also ist das nicht korrekt!

Aus diesem Grund benötigen wir geeignete Verteilungen , die eine Quelle einheitlicher zufälliger Ganzzahlen verwenden und diese wie Uniform[0,2]im Beispiel in unsere gewünschte Verteilung umwandeln. Überlassen Sie dies am besten einer guten Bibliothek!

Motoren

Das Herzstück aller Zufälligkeit ist also ein guter Pseudozufallszahlengenerator, der eine Folge von Zahlen erzeugt, die gleichmäßig über ein bestimmtes Intervall verteilt sind und idealerweise eine sehr lange Periode haben. Die Standardimplementierung von rand()ist oft nicht die beste, und daher ist es gut, eine Wahl zu haben. Linear-kongruent und der Mersenne-Twister sind zwei gute Optionen (LG wird auch häufig von verwendet rand()). Auch hier ist es gut, die Bibliothek damit umgehen zu lassen.

Wie es funktioniert

Einfach: Stellen Sie zuerst einen Motor auf und setzen Sie ihn ein. Der Startwert bestimmt vollständig die gesamte Folge von "Zufallszahlen". Verwenden Sie daher /dev/urandomjedes Mal eine andere (z. B. entnommene ) und b) speichern Sie den Startwert, wenn Sie eine Folge von Zufallswahlen neu erstellen möchten.

#include <random>

typedef std::mt19937 MyRNG;  // the Mersenne Twister with a popular choice of parameters
uint32_t seed_val;           // populate somehow

MyRNG rng;                   // e.g. keep one global instance (per thread)

void initialize()
{
  rng.seed(seed_val);
}

Jetzt können wir Distributionen erstellen:

std::uniform_int_distribution<uint32_t> uint_dist;         // by default range [0, MAX]
std::uniform_int_distribution<uint32_t> uint_dist10(0,10); // range [0,10]
std::normal_distribution<double> normal_dist(mean, stddeviation);  // N(mean, stddeviation)

... und benutze die Engine, um Zufallszahlen zu erstellen!

while (true)
{
  std::cout << uint_dist(rng) << " "
            << uint_dist10(rng) << " "
            << normal_dist(rng) << std::endl;

}

Parallelität

Ein weiterer wichtiger Grund, <random>den herkömmlichen zu bevorzugen, rand()ist, dass es jetzt sehr klar und offensichtlich ist, wie die Generierung von Zufallszahlen threadsicher gemacht werden kann: Stellen Sie entweder jedem Thread eine eigene thread-lokale Engine zur Verfügung, die auf einem thread-lokalen Seed basiert, oder synchronisieren Sie den Zugriff zum Motorobjekt.

Sonstiges

  • Ein interessanter Artikel über TR1 zufällig auf Codeguru.
  • Wikipedia hat eine gute Zusammenfassung (danke, @Justin).
  • Grundsätzlich sollte jeder Motor a eingeben result_type, was der richtige Integraltyp für das Saatgut ist. Ich glaube , ich hatte eine Buggy Umsetzung einmal die mich gezwungen , für den Samen zu zwingen , std::mt19937um uint32_tauf x64, schließlich dieses Problem behoben werden soll , und man kann sagen , MyRNG::result_type seed_valund damit den Motor macht sehr leicht austauschbar.
Kerrek SB
quelle
Wieder einmal schlägt mich Kerrek mit einer viel besseren Antwort als die, an der ich gearbeitet habe. +1
Justin 18
@Justin: Ich bin sicher, ich habe eine Menge Dinge verpasst. Fühlen Sie sich frei, diesem Thema weitere Aspekte hinzuzufügen! :-)
Kerrek SB
13
Für den Teil "irgendwie bevölkern" denke ich std::random_deviceeher erwähnenswert als/dev/urandom
Cubbi
2
Ein Beispiel std::random_devicedafür finden Sie hier .
WKS
1
Der Code im Wikipedia-Artikel ist fehlerhaft. random und random2 sind identisch. Aus den Kommentaren im Code-Snippet geht hervor, dass der Autor nicht versteht, wie die Funktionen in <random> verwendet werden.
user515430
3

Ein Zufallszahlengenerator ist eine Gleichung, die Ihnen bei gegebener Zahl eine neue Zahl gibt. Normalerweise geben Sie entweder die erste Nummer an oder sie wird aus der Systemzeit abgerufen.

Jedes Mal, wenn Sie nach einer neuen Nummer fragen, wird die vorherige Nummer verwendet, um die Gleichung auszuführen.

Ein Zufallszahlengenerator wird nicht als sehr gut angesehen, wenn er dazu neigt, dieselbe Zahl häufiger als andere Zahlen zu erzeugen. dh wenn Sie eine Zufallszahl zwischen eins und 5 wollten und diese Zahlenverteilung hatten:

  • 1: 1%
  • 2: 80%
  • 3: 5%
  • 4: 5%
  • 5: 9%

2 wird weitaus häufiger generiert als jede andere Nummer, daher ist es wahrscheinlicher, dass es produziert wird als andere Nummern. Wenn alle Zahlen gleich wären, hätten Sie eine 20% ige Chance, jedes Mal jede Zahl zu erhalten. Anders ausgedrückt ist die obige Verteilung sehr ungleichmäßig, da 2 bevorzugt wird. Eine Verteilung mit allen 20% wäre gerade.

Wenn Sie eine echte Zufallszahl wünschen, ziehen Sie normalerweise Daten von etwas wie Wetter oder einer anderen natürlichen Quelle anstatt von einem Zufallszahlengenerator.

N / A
quelle
8
Die meisten Zufallszahlengeneratoren erzeugen gute gleichmäßige Verteilungen. Sie sind einfach nicht zufällig; Das Problem ist, dass sie berechnet werden und Sie daher die nächste Zahl erraten können, wenn genügend Zahlen in der Sequenz vorhanden sind (diese Tatsache macht sie für die Sicherheit schlecht, wenn wirklich zufällige Zahlen erforderlich sind). Für Spiele und Sachen sollte es dir gut gehen.
Martin York
5
Ich bin mir ziemlich sicher, dass das OP nach spezifischen Informationen zu den im C ++ <random> -Header bereitgestellten Funktionen fragt. Diese Antwort betrifft nicht einmal die Programmierung, geschweige denn C ++.
Benjamin Lindley
1
@Martin: Sicherheit erfordert nicht unbedingt eine Quelle für wirklich zufällige Zahlen. AES im Zählermodus (zum Beispiel) kann sehr gut funktionieren, obwohl es deterministisch ist. Es erfordert eine angemessene Menge an Entropie im Schlüssel, aber keine echte Zufälligkeit.
Jerry Coffin
@ Benjamin Lindley: Vergiss es. Lesen Sie einfach noch einmal und stellen Sie fest, dass ich falsch lag.
N_A