2017-02-21 3 views
2

Diese Frage vor (stackoverflow) gefragt wurde, aber die (angenommen) Antwort ist nicht zufrieden stellend.Speichern und Laden von Random Number Generator Staat in C++ 11

Das folgende Beispiel speichert und lädt den Zustand, sondern in Abhängigkeit von der Anzahl der generierten Werte funktioniert es oder es funktioniert nicht:

#include <fstream> 
#include <iostream> 
#include <random> 
#include <cassert> 

int main() 
{ 
    const int preN = 4; 
    const int middleN = 0; 

    // initialize randGen 
    std::mt19937 randGen1; 
    std::normal_distribution<double> distribution1; 


    // print some initial random numbers 
    for (int i=0;i<preN;++i) 
    std::cout << distribution1(randGen1)<<" "; 

    // save state 
    std::cout << std::endl << "Saving...\n"; 
    { 
    std::ofstream fout("seed.dat"); 
    fout << randGen1; 
    } 

    // maybe advance randGen1 
    for (int i=0;i<middleN;++i) 
    std::cout << distribution1(randGen1)<<" "; 

    // load saved state into randGen2 
    std::cout << std::endl << "Loading...\n"; 
    std::ifstream fin("seed.dat"); 
    std::mt19937 randGen2; 
    fin >> randGen2; 
    std::normal_distribution<double> distribution2; 

    // are both randGen equal? 
    assert(randGen1 == randGen2); 

    // print numbers from both generators 
    std::cout << "Generator1\tGenerator2\n"; 
    std::cout << distribution1(randGen1) << "\t" 
      << distribution2(randGen2) << "\n"; 

    return 0; 

}  

Mit diesen Parametern es wie erwartet funktioniert. wenn ich preN=3 gesetzt Allerdings sieht die Ausgabe wie:

0.13453 -0.146382 0.46065 
Saving... 

Loading... 
Generator1 Generator2 
-1.87138 0.163712 

Warum hat die Assertion nicht gelten? Jetzt stelle ich preN=3 und middleN=1 und der Ausgang ist

0.13453 -0.146382 0.46065 
Saving... 
-1.87138 
Loading... 
Generator1 Generator2 
0.163712 0.163712 

Wenn ich middleN auf etwas größer als 1 gesetzt die assert gilt. Kann mir jemand erklären, was vor sich geht? Was mache ich falsch oder nicht?

Getestet mit GCC5.4.0 und CLANG3.8.0 auf Linux

Antwort

4

Das Problem ist nicht die zufällige Zustand des Zahlengenerators. Das Problem ist, Ihre staatliche Verteilung. Ja, Distributionen können auch einen Status haben.

Sie können die gleichen Werte erhalten, indem die Normalverteilung des Staates mit reset zurückgesetzt wird. Alternativ können Sie auch die Verteilung des Staates preserve and reconstitute, << und >> verwenden.

+0

es zu Versuchte (weil das Verhalten faszinierend aussah und ich C nicht versuchen ++ für eine lange Zeit) und kann sagen, für sicher, dass sich ein uniform-dist anders verhält! – sascha

+0

@Sascha: Ich bin mir nicht sicher, was Sie meinen, dass es sich anders verhält. –

+0

, dass es wahrscheinlich keinen internen Staat hat, die (viel einfacher als normal-dist) zählt, aber das ist nur empirische Beobachtung. Es war nur mein erster Versuch. Vielleicht tut es das auch. Ignoriere meinen Kommentar. Gute Antwort! – sascha

1

Dank der Antwort von Nicol Bolas oben, kann ich den korrigierten Code unten hinzufügen:

#include <fstream> 
#include <iostream> 
#include <random> 
#include <cassert> 

int main() 
{ 
    const int preN = 7; 
    const int middleN = 0; 

    // initialize another randGen 
    std::mt19937 randGen1; 
    std::normal_distribution<double> distribution1; 

    // print some initial random numbers 
    for (int i=0;i<preN;++i) 
    std::cout << distribution1(randGen1)<<" "; 

    // save state 
    std::cout << std::endl << "Saving...\n"; 
    { 
    std::ofstream fout("seed.dat"); 
    fout << randGen1; 
    fout.close(); 
    std::ofstream fout2("distribution.dat"); 
    fout2 << distribution1; 
    fout2.close(); 
    } 

    // maybe advance randGen 
    for (int i=0;i<middleN;++i) 
    std::cout << distribution1(randGen1)<<" "; 

    // load saved state into randGen2 
    std::cout << std::endl << "Loading...\n"; 
    std::mt19937 randGen2; 
    std::normal_distribution<double> distribution2; 
    { 
    std::ifstream fin("seed.dat"); 
    fin >> randGen2; 
    fin.close(); 
    std::ifstream fin2("distribution.dat"); 
    fin2 >> distribution2; 
    fin2.close(); 
    } 

    // are both randGen equal? 
    assert(randGen1 == randGen2); 
    assert(distribution1 == distribution2); 

    // print numbers from both generators 
    std::cout << "Generator1\tGenerator2\n"; 
    std::cout << distribution1(randGen1) << "\t" 
      << distribution2(randGen2) << "\n"; 

    return 0; 
}