
Gary Richardson
Ich brauche einen “guten” Weg, um den Pseudozufallszahlengenerator in C++ zu initialisieren. Ich habe gefunden ein Artikel das besagt:
Um zufallsähnliche Zahlen zu generieren, wird srand normalerweise mit einem bestimmten Wert initialisiert, wie z. B. denen, die mit der Ausführungszeit zusammenhängen. Beispielsweise ist der von der Funktion time (in Header ctime deklariert) zurückgegebene Wert jede Sekunde anders, was für die meisten Randoming-Anforderungen ausreichend ausgeprägt ist.
Unixtime ist für meine Anwendung nicht ausgeprägt genug. Wie kann man das besser initialisieren? Bonuspunkte, wenn es portabel ist, aber der Code wird hauptsächlich auf Linux-Hosts ausgeführt.
Ich dachte daran, etwas PID/Unixtime-Mathematik zu machen, um ein Int zu bekommen, oder möglicherweise Daten daraus zu lesen /dev/urandom
.
Danke!
BEARBEITEN
Ja, ich starte meine Anwendung tatsächlich mehrmals pro Sekunde und bin auf Kollisionen gestoßen.

Jonathan Wright
Dies ist, was ich für kleine Befehlszeilenprogramme verwendet habe, die häufig ausgeführt werden können (mehrmals pro Sekunde):
unsigned long seed = mix(clock(), time(NULL), getpid());
Wo Mischung ist:
// Robert Jenkins' 96 bit Mix Function
unsigned long mix(unsigned long a, unsigned long b, unsigned long c)
{
a=a-b; a=a-c; a=a^(c >> 13);
b=b-c; b=b-a; b=b^(a << 8);
c=c-a; c=c-b; c=c^(b >> 13);
a=a-b; a=a-c; a=a^(c >> 12);
b=b-c; b=b-a; b=b^(a << 16);
c=c-a; c=c-b; c=c^(b >> 5);
a=a-b; a=a-c; a=a^(c >> 3);
b=b-c; b=b-a; b=b^(a << 10);
c=c-a; c=c-b; c=c^(b >> 15);
return c;
}

Martin York
Die beste Antwort ist zu <random>
. Wenn Sie eine Pre-C++11-Version verwenden, können Sie sich alternativ die Boost-Zufallszahlen ansehen.
Aber wenn wir reden rand()
und srand()
Die Beste Der einfachste Weg ist nur zu verwenden time()
:
int main()
{
srand(time(nullptr));
...
}
Stellen Sie sicher, dass Sie dies zu Beginn Ihres Programms tun und nicht bei jedem Anruf rand()
!
Randnotiz:
HINWEIS: Es gibt eine Diskussion in den Kommentaren unten darüber, dass dies unsicher ist (was wahr ist, aber letztendlich nicht relevant ist (weiterlesen)). Eine Alternative ist also das Seeden vom Zufallsgerät /dev/random
(oder einen anderen sicheren echten (er) Zufallszahlengenerator). ABER: Lassen Sie sich davon nicht in falscher Sicherheit wiegen. Das ist rand()
wir benutzen. Selbst wenn Sie es mit einem brillant generierten Seed versehen, ist es immer noch vorhersehbar (wenn Sie einen Wert haben, können Sie die vollständige Folge der nächsten Werte vorhersagen). Dies ist nur für die Generierung sinnvoll "pseudo"
zufällige Werte.
Wenn Sie “sicher” wollen, sollten Sie wahrscheinlich verwenden <random>
(Obwohl ich auf einer Website mit Sicherheitsinformationen noch etwas mehr lesen würde). Sehen Sie sich die folgende Antwort als Ausgangspunkt an: https://stackoverflow.com/a/29190957/14065 für eine bessere Antwort.
Sekundäre Anmerkung: Die Verwendung eines zufälligen Geräts löst die Probleme mit dem Starten mehrerer Kopien pro Sekunde tatsächlich besser als mein ursprünglicher Vorschlag unten (nur nicht das Sicherheitsproblem).
Zurück zur ursprünglichen Geschichte:
Bei jedem Start gibt time() einen eindeutigen Wert zurück (es sei denn, Sie starten die Anwendung mehrmals pro Sekunde). In 32-Bit-Systemen wird es nur etwa alle 60 Jahre wiederholt.
Ich weiß, Sie denken nicht, dass die Zeit einzigartig genug ist, aber ich kann das kaum glauben. Aber es ist bekannt, dass ich falsch liege.
Wenn Sie viele Kopien Ihrer Anwendung gleichzeitig starten, können Sie einen Timer mit einer feineren Auflösung verwenden. Aber dann riskieren Sie eine kürzere Zeitspanne, bevor sich der Wert wiederholt.
OK, also wenn Sie wirklich glauben, dass Sie mehrere Anwendungen pro Sekunde starten.
Verwenden Sie dann eine feinere Körnung auf dem Timer.
int main()
{
struct timeval time;
gettimeofday(&time,NULL);
// microsecond has 1 000 000
// Assuming you did not need quite that accuracy
// Also do not assume the system clock has that accuracy.
srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
// The trouble here is that the seed will repeat every
// 24 days or so.
// If you use 100 (rather than 1000) the seed repeats every 248 days.
// Do not make the MISTAKE of using just the tv_usec
// This will mean your seed repeats every second.
}

Evan Teran
Wenn Sie einen besseren Zufallszahlengenerator benötigen, verwenden Sie nicht die libc rand. Verwenden Sie stattdessen einfach so etwas wie /dev/random
oder /dev/urandom
direkt (einlesen int
direkt daraus oder so).
Der einzige wirkliche Vorteil von libc rand ist, dass er bei gegebenem Seed vorhersehbar ist, was beim Debuggen hilft.
Unter Windows:
srand(GetTickCount());
liefert einen besseren Samen als time()
seit seiner in Millisekunden.

Namen53
C++11 random_device
Wenn Sie eine angemessene Qualität benötigen, sollten Sie rand() überhaupt nicht verwenden. Sie sollten die verwenden <random>
Bücherei. Es bietet viele großartige Funktionen, wie z. B. eine Vielzahl von Engines für unterschiedliche Qualitäts-/Größen-/Leistungskompromisse, Wiedereintritt und vordefinierte Verteilungen, damit Sie am Ende nichts falsch machen. Abhängig von Ihrer Implementierung kann es sogar einen einfachen Zugriff auf nicht deterministische Zufallsdaten (z. B. /dev/random) bieten.
#include <random>
#include <iostream>
int main() {
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);
std::uniform_int_distribution<> dist{1,100};
for (int i=0; i<50; ++i)
std::cout << dist(eng) << '\n';
}
eng
ist eine Quelle der Zufälligkeit, hier eine eingebaute Implementierung von Mersenne Twister. Wir setzen es mit random_device, das in jeder anständigen Implementierung ein nicht deterministisches RNG sein wird, und seed_seq, um mehr als 32-Bit-Zufallsdaten zu kombinieren. Zum Beispiel greift random_device in libc++ standardmäßig auf /dev/urandom zu (obwohl Sie ihm stattdessen eine andere Datei für den Zugriff geben können).
Als Nächstes erstellen wir eine Verteilung, sodass bei gegebener Zufälligkeitsquelle wiederholte Aufrufe der Verteilung eine gleichmäßige Verteilung von Ints von 1 bis 100 erzeugen. Dann fahren wir damit fort, die Verteilung wiederholt zu verwenden und die Ergebnisse auszugeben.

Benutzer39307
Der beste Weg ist, einen anderen Pseudozufallszahlengenerator zu verwenden. Mersenne Twister (und Wichmann-Hill) ist meine Empfehlung.
http://en.wikipedia.org/wiki/Mersenne_twister

FL4SOF
Ich schlage vor, Sie sehen die Datei unix_random.c im Mozilla-Code. (schätze, es ist mozilla/security/freebl/ …) es sollte in der freebl-Bibliothek sein.
dort verwendet es Systemaufrufinformationen (wie pwd, netstat ….), um Rauschen für die Zufallszahl zu erzeugen; es ist so geschrieben, dass es die meisten Plattformen unterstützt (was mir einen Bonuspunkt einbringen kann: D).
9926200cookie-checkEmpfohlene Methode zum Initialisieren von Sand?yes
Warum ist time() nicht genug? Starten Sie die Anwendung mehrmals pro Sekunde? Beachten Sie, dass Sie srand() nur EINMAL in einer Anwendung aufrufen sollten.
– Martin York
27. November 2008 um 5:33 Uhr
Wenn time() – oder gettimeofday() – nicht ausreicht, dann ist rand() wahrscheinlich nicht gut genug für Sie. Dieser PRNG muss überhaupt nicht sehr gut sein. Kryptografische Zufälligkeit ist schwierig – verwenden Sie eine kryptografische Bibliothek.
– Jonathan Leffler
27. November 2008 um 7:19 Uhr
Tatsächlich hält zumindest MS CRT den Seed in TLS, also müssten Sie in diesem Fall tatsächlich srand() EINMAL für jeden Thread initialisieren. Ich bin mir jedoch nicht sicher, wie GCC den Seed speichert.
– Andreas Magnusson
27. November 2008 um 9:32 Uhr
Weitere Informationen zum Initialisieren von srand() mit Mikrosekunden: guyrutenberg.com/2007/09/03/seeding-srand
– nichts-besonderes-hier
7. April 2013 um 17:42 Uhr
Verwandt: Wie ich Hacker News gehackt habe. HN verwendete die Zeit in Millisekunden als Startwert und verwendete dann den RNG, um Anmelde-Cookies zu generieren. Der Angreifer könnte den Seed wiederherstellen, indem er sich bei seinem Konto anmeldet, ein Cookie erhält, dann mögliche Seeds aufzählt und jeden mit dem Cookie vergleicht, bis eine Übereinstimmung gefunden wird. Mit dem richtigen Startwert könnten sie dann Cookies anderer Benutzer vorhersagen und als diese Benutzer Aktionen auf der Website ausführen.
– Bain
15. November 2019 um 11:01 Uhr