Der folgende Code soll eine Liste von fünf Pseudozufallszahlen im Intervall [1.100] generieren. Ich setze das default_random_engine
mit time(0)
, was die Systemzeit in Unix-Zeit zurückgibt . Wenn ich dieses Programm unter Windows 7 mit Microsoft Visual Studio 2013 kompiliere und ausführe, funktioniert es wie erwartet (siehe unten). Wenn ich dies in Arch Linux mit dem g ++ - Compiler mache, verhält es sich jedoch seltsam.
Unter Linux werden jedes Mal 5 Zahlen generiert. Die letzten 4 Zahlen sind bei jeder Ausführung unterschiedlich (wie es häufig der Fall ist), aber die erste Zahl bleibt gleich.
Beispielausgabe von 5 Ausführungen unter Windows und Linux:
| Windows: | Linux:
---------------------------------------
Run 1 | 54,01,91,73,68 | 25,38,40,42,21
Run 2 | 46,24,16,93,82 | 25,78,66,80,81
Run 3 | 86,36,33,63,05 | 25,17,93,17,40
Run 4 | 75,79,66,23,84 | 25,70,95,01,54
Run 5 | 64,36,32,44,85 | 25,09,22,38,13
Hinzu kommt, dass diese erste Zahl unter Linux regelmäßig um eins erhöht wird. Nachdem ich die obigen Ausgaben erhalten hatte, wartete ich ungefähr 30 Minuten und versuchte erneut festzustellen, dass sich die erste Zahl geändert hatte und nun immer als 26 generiert wurde. Sie wurde in regelmäßigen Abständen um 1 erhöht und liegt nun bei 32. Es scheint zu entsprechen mit dem sich ändernden Wert von time(0)
.
Warum ändert sich die erste Zahl selten über Läufe hinweg und erhöht sich dann, wenn dies der Fall ist, um 1?
Der Code. Es druckt die 5 Zahlen und die Systemzeit sauber aus:
#include <iostream>
#include <random>
#include <time.h>
using namespace std;
int main()
{
const int upper_bound = 100;
const int lower_bound = 1;
time_t system_time = time(0);
default_random_engine e(system_time);
uniform_int_distribution<int> u(lower_bound, upper_bound);
cout << '#' << '\t' << "system time" << endl
<< "-------------------" << endl;
for (int counter = 1; counter <= 5; counter++)
{
int secret = u(e);
cout << secret << '\t' << system_time << endl;
}
system("pause");
return 0;
}
sizeof(time_t)
gegensizeof(default_random_engine::result_type)
?default_random_engine
dies auf diesen beiden Plattformen völlig unterschiedlich ist.Antworten:
Folgendes ist los:
default_random_engine
in libstdc ++ (GCCs Standardbibliothek) istminstd_rand0
dies eine einfache lineare kongruente Engine:Die Art und Weise, wie diese Engine Zufallszahlen generiert, ist x i + 1 = (16807x i + 0) mod 2147483647.
Wenn sich die Samen um 1 unterscheiden, unterscheidet sich die erste generierte Zahl daher meistens um 16807.
Die Reichweite dieses Generators beträgt [1, 2147483646]. Libstdc ++
uniform_int_distribution
ordnet es im Wesentlichen einer Ganzzahl im Bereich [1, 100] zu: Generieren Sie eine Zahln
. Wenn die Anzahl nicht größer als 2147483600 ist, kehren Sie zurück(n - 1) / 21474836 + 1
. Andernfalls versuchen Sie es erneut mit einer neuen Nummer.Es sollte leicht zu erkennen sein, dass in den allermeisten Fällen zwei
n
s, die sich nur um 16807 unterscheiden, nach diesem Verfahren die gleiche Zahl in [1, 100] ergeben. Tatsächlich würde man erwarten, dass sich die generierte Zahl etwa alle 21474836/16807 = 1278 Sekunden oder 21,3 Minuten um eins erhöht, was ziemlich gut mit Ihren Beobachtungen übereinstimmt.MSVCs
default_random_engine
istmt19937
, die dieses Problem nicht haben.quelle
rand()
% 7 immer 0rand()
ist etwas verständlich (es ist hoffnungsloser Legacy-Mist). Die Verwendung eines Shit-Tier-PRNG für etwas Neues ist unentschuldbar. Ich würde dies sogar als Standardverletzung betrachten, da der Standard verlangt, "zumindest ein akzeptables Motorverhalten für eine relativ gelegentliche, unsachgemäße und / oder leichte Verwendung bereitzustellen". Dies bietet diese Implementierung nicht, da sie selbst für triviale Anwendungsfälle wie Ihrrand % 7
Beispiel katastrophal fehlschlägt .rand()
genau verständlich? Ist es nur, weil niemand daran gedacht hätte?srand
ist zu klein, um leicht einzigartige Samen zu erzeugen. 3) Es gibt eine Ganzzahl mit einer durch die Implementierung definierten Obergrenze zurück, die der Aufrufer irgendwie auf eine Zahl im gewünschten Bereich reduzieren muss. Dies ist bei richtiger Ausführung mehr Arbeit als das Schreiben eines Ersatzes mit einer vernünftigen API fürrand()
4) Es verwendet den globalen veränderlichen StatusDie
std::default_random_engine
Implementierung ist definiert. Verwenden Siestd::mt19937
oderstd::mt19937_64
stattdessen.Wenn
std::time
diectime
Funktionen nicht sehr genau sind, verwenden Sie<chrono>
stattdessen die in der Kopfzeile definierten Typen :quelle
std::random_device
anstelle von current_time Ihren Zufallsgenerator zu verwenden. Bitte überprüfen Sie alle Referenzbeispiele zu Random.ctime
beträgt 1 Sekunde. Die Granularität derstd::chrono
Implementierungen ist benutzerdefiniertstd::high_resolution_clock
und standardmäßig für (in Visual Studio ist es ein Typedef fürstd::steady_clock
) Nanosekunden, kann jedoch eine viel kleinere Messung wählen, daher viel präziser.Unter Linux ist die Zufallsfunktion keine Zufallsfunktion im probabilistischen Sinne, sondern ein Pseudozufallszahlengenerator. Es wird mit einem Samen gesalzen, und basierend auf diesem Samen sind die produzierten Zahlen pseudozufällig und gleichmäßig verteilt. Der Linux-Weg hat den Vorteil, dass bei der Gestaltung bestimmter Experimente unter Verwendung von Informationen aus Populationen die Wiederholung des Experiments mit bekannter Optimierung der Eingabeinformationen gemessen werden kann. Wenn das endgültige Programm für Tests im realen Leben bereit ist, kann das Salz (Seed) erstellt werden, indem der Benutzer aufgefordert wird, die Maus zu bewegen, die Mausbewegung mit einigen Tastenanschlägen zu mischen und seit Beginn von einen Strich Mikrosekundenzahlen hinzuzufügen das letzte Einschalten.
Windows-Zufallszahlen-Seed wird aus der Sammlung von Maus-, Tastatur-, Netzwerk- und Tageszeitnummern erhalten. Es ist nicht wiederholbar. Dieser Salzwert kann jedoch auf einen bekannten Samen zurückgesetzt werden, wenn, wie oben erwähnt, einer an der Gestaltung eines Experiments beteiligt ist.
Oh ja, Linux hat zwei Zufallszahlengeneratoren. Zum einen ist der Standardwert Modulo 32 Bit und zum anderen Modulo 64 Bit. Ihre Wahl hängt von den Genauigkeitsanforderungen und der Rechenzeit ab, die Sie für Ihre Tests oder die tatsächliche Verwendung benötigen.
quelle
collection of mouse, keyboard, network and time of day numbers