Warum bekomme ich für jeden Lauf mit std :: random_device mit mingw gcc4.8.1 die gleiche Sequenz?

70

Ich benutze den folgenden Code, um die C ++ - <random>Bibliothek zu testen .

Warum erhalte ich für jeden Lauf der kompilierten ausführbaren Datei genau die gleiche Reihenfolge? Ist rd()bei der Zusammenstellung deterministisch? Wie erhalte ich für jeden Lauf eine andere Ausgabe?

GCC 4.8.1 unter Windows 7 64bit. Verwenden der MinGW-Distribution von http://nuwen.net/mingw.html .

BEARBEITEN: Ich habe den gleichen Stückcode mit Visual Studio getestet. Es gibt kein Problem. Die Ausgaben sind nicht deterministisch. Dies könnte ein Fehler in mingw gcc 4.8.1 sein, den ich verwendet habe.

#include <iostream>
#include <random>
using namespace std;

int main(){
 random_device rd;
 mt19937 mt(rd());
 uniform_int_distribution<int> dist(0,99);
 for (int i = 0; i< 16; ++i){
    cout<<dist(mt)<<" ";
 }
 cout <<endl;
}
Ahala
quelle
5
Plattform und Compiler bitte. Dies sollte auch bei nicht passieren entropy() == 0. Wenn ja, ist das ein Fehler.
Konrad Rudolph
9
@ MM. Nein, so random_devicefunktioniert das nicht .
Konrad Rudolph
5
Könnten Sie den Compiler _GLIBCXX_USE_RANDOM_TR1bitte dazu bringen, den Inhalt des Makros zu drucken ? Wenn es 0 ist, wird mt19937 mit einem festen Startwert als Fallback verwendet.
Konrad Rudolph
3
Fehler ist immer noch in mingw-w64 mit gcc 4.9.2
MM
4
Hat jemand versucht, einen Fehler an GCC zu melden, damit er behoben werden kann? Oder ist das zu viel verlangt?
Jonathan Wakely

Antworten:

34

Von http://en.cppreference.com/w/cpp/numeric/random/random_device :

Beachten Sie, dass std :: random_device in Form einer Pseudozufallszahlen-Engine implementiert werden kann, wenn der Implementierung keine nicht deterministische Quelle (z. B. ein Hardwaregerät) zur Verfügung steht.

Ich würde allerdings erwarten, dass eine anständige Implementierung zumindest das RNG auslöst.

Bearbeiten: Ich vermute, sie haben sich bewusst dafür entschieden, jedes Mal dieselbe Sequenz zu liefern, um die Tatsache zu verdeutlichen, dass der Stream nicht so zufällig war, wie versprochen.

Mark Ransom
quelle
10
Genau. Die Fallback-Implementierung von stdlibc ++ verwendet einen konstanten Startwert, der mir nicht so schlau erscheint (und nicht erklärt wird).
Konrad Rudolph
17
Der eigentliche Fehler besteht darin, diesen pseudozufälligen Fallback überhaupt zu haben.
Ypnos
6
@ypnos: Der Standard muss etwas tun, um den Fall einer C ++ - Implementierung auf einer deterministischen Plattform abzudecken. Dies auf einer realen Plattform zu tun, ist jedoch ein großes Problem bei der Qualität der Implementierung. Siehe auch Wie man den mt19937 PRNG kurz, portabel und gründlich aussät? .
Peter Cordes
26

Ich habe eine bestätigte Antwort von STL von MSFT erhalten :

Im Gegensatz zu VC hat GCC random_device unter Windows nicht unbestimmt implementiert. Boost hat, so dass Sie Boost.Random verwenden können.

Ahala
quelle
1
Ich habe noch kein geeignetes Dokument gefunden, das angibt, welche Boost-Lib-ls und welche Order-Boosts -l's in gcc benötigt werden, um Verbindungsfehler zu vermeiden, und jedes System -l ist ebenfalls erforderlich. Allein das Hinzufügen von -lboost-random-mgw48-mt-d-1_57 führte dazu, dass der Linker sich beschwerte, dass es keinen boost :: random :: random_device () und keinen boost :: random :: ~ random_device () gab
Brian Jack
3

Dies ist ein GCC-Fehler , der in GCC 9.2 behoben wurde.

Wenn Sie dieses Problem haben, aktualisieren Sie Ihren Compiler. (Sie können beispielsweise ein neues GCC von MSYS2 erhalten.)

HolyBlackCat
quelle
@Northerner Run pacman -Syuu. Es gibt eine Änderung, dass das Terminal (und alle msys2-Programme) geschlossen werden, um fortzufahren. In einer älteren Version werden Sie aufgefordert, dies manuell zu tun. In diesem Fall müssen Sie MSYS2 neu starten und denselben Befehl erneut ausführen, um das Update abzuschließen.
HolyBlackCat
Das Update schlägt fehl stackoverflow.com/questions/63201980/… Auch ich habe bereits GCC 9.1 und random_devicefunktioniert immer noch nicht.
Nordländer
@northerner Nun, wie gesagt, es wurde in GCC 9.2 behoben und Ihre Version ist älter als diese. Versuchen Sie, MSYS2 neu zu installieren.
HolyBlackCat
2
  1. GCC implementiert rd.entropy () nicht korrekt - es gibt immer 0 zurück (zumindest unter Mac OS X).

  2. Leider scheint es keine Möglichkeit zu geben, zusätzliche Entropie in random_device zu mischen, was wichtig ist, da es normalerweise / häufig (siehe Linux / dev / random und / dev / urandom sowie die Intel RDRAND-Implementierung) einen Pseudozufallszahlengenerator implementiert unter der Haube. Ich möchte in der Lage sein, seine Ausgabe zu verbessern, indem ich etwas injiziere, das ich für zufällig halte, um es mit dem zu mischen, was seine Entropiequelle erzeugt. Da dieses Gerät (oder Kernelmodul) intern einen kryptografischen Algorithmus zum Verarbeiten der Entropiebits implementiert, die es zur Erzeugung seiner Ausgabe erhält, möchte ich diesen Prozess mehr "randomisieren" können, indem ich meine eigenen Daten injiziere, um sie mit irgendetwas zu mischen Entropie, die das Gerät auswählt. Betrachten Sie beispielsweise Java SecureRandom (). Sie können nicht einstellen das Seed (das es tatsächlich in PRNG konvertieren würde), aber es würde glücklich mischen, was Sie bereitstellen, mit dem, was es verwendet, um seine Ausgabe noch mehr zu "randomisieren".

  3. Ich persönlich bevorzuge RDRAND. Eine kleine Assemblybibliothek mit einer kompakten C-Schnittstelle. Hier sind die Referenzen:

    David Johnson von Intel erklärt RDRAND zu Stackoverflow

    Stackoverflow-Zeiger auf die RDRAND-Bibliotheksquelle für Windows, Linux und Mac OS X.

    Intel-Blog über die RDRAND-Bibliothek und ein Download-Link

Maus
quelle
6
Es macht keinen Sinn zu säen random_device. Wenn es einen Startwert erfordert, dann ist es ein Pseudozufallsgenerator, kein echter Zufallszahlengenerator, wie random_devicees sein soll.
Chris Beck
3
"Seed" war ein unglücklicher Begriff. Sie "säen" kein "wahres" random_device. Da zufällige Geräte wie Linux (und sogar RDRAND, das von der Firmware implementiert ist) Softwarealgorithmen zwischen ihren Entropiequellen und ihrer Ausgabe enthalten, die den Benutzern zur Verfügung stehen, kann das Einmischen von Zufälligkeit / Entropie aus anderen Quellen das Ergebnis nicht beeinträchtigen und kann es manchmal auch Verbessere es. Ich denke, Sie sollten Ihre Ablehnung zurückziehen, wenn Sie ehrlich sind.
Maus
2
Ich denke, die Antwort ist verwirrend geschrieben. Wenn Sie sie umschreiben, kann ich meine Ablehnung zurückziehen. Es gibt einen Unterschied zwischen der Erzeugung von Pseudozufällen und der Extraktion von Zufälligkeiten . Theoretisch funktioniert es so. Bei einer schwach zufälligen Quelle, z. B. 1000 Bits mit nur 100 Entropiebits, möchten Sie zunächst einen Extraktor verwenden, um ~ 50 Bits mit ~ 50 Entropiebits zu erhalten. In der Praxis wird hierfür eine kryptografische Hash-Funktion verwendet. Dann kann das Ergebnis als Startwert für einen Generator verwendet werden, der die 50 Bits auf viele, viele weitere Bits für die Verwendung in Ihrer Anwendung ausdehnt. (Zahlen erfunden.)
Chris Beck
3
Nett. Ich war nicht bewusst , dass Sie konnte schreiben zu /dev/random. Jetzt weiß ich es besser: eine Datei als Entropiequelle hinzufügen und warum schreibe / dev / random ... . Das XORing der zusätzlichen Entropie in das Ergebnis ist ein guter und effizienter Weg - mit dem Nachteil, explizit zu sein.
Maus
2
Ich denke, das Java-Modell ist das beste, weil es dem Rest des verwendeten Programms ermöglicht, SecureRandomsich all dieser Details und Verbesserungen nicht bewusst zu sein und einfach die Standardschnittstelle der Standardklasse unverändert zu verwenden. Ein weiterer Vorteil der Java SecureRandom-API besteht darin, dass sie durch "schlechte" Zufälligkeitseingaben des Benutzers nicht beschädigt werden kann. Die SecureRandom-Ausgabe kann nur durch zusätzliche Eingabe verbessert werden (oder bei gleicher Qualität bleiben).
Maus