Zufallszahlen generieren mit std::generate -> immer die gleichen Zahlen



  • Hi Forum,

    ich habe folgenden C++ Code im Forum gefunden und nach meinen Wuenschen modifiziert:

    boost::dynamic_bitset<> generate(boost::dynamic_bitset<>::size_type n)
    { 
       static std::random_device rd;
    
       const int bpb  = boost::dynamic_bitset<>::bits_per_block; 
       std::vector<boost::dynamic_bitset<>::block_type>arr;
       arr.resize(n%bpb ? n/bpb+1 : n/bpb); 
    
       static std::independent_bits_engine<std::minstd_rand, 
    		 boost::dynamic_bitset<>::bits_per_block, 
    		 boost::dynamic_bitset<>::block_width_type> engine(rd); 
    
       std::generate(std::begin(arr), std::end(arr), engine); 
    
       boost::dynamic_bitset<> ret(std::begin(arr), std::end(arr)); 
       return ret; 
    }
    

    Jedoch werden immer die gleichen Zahlen generiert, wenn ich die Zeile std::generate mit folgender ersetze, geht es auf einmal:

    for(auto i=arr.begin();i!=arr.cend();i++)
    	(*i) = engine();
    

    Warum funktioniert es nicht mit std::generate?

    Vielen Dank fuer eure Hilfe



  • Erstens: Das sieht verdächtig nach meinem Code aus, ich erinnere mich nur nicht woher... ahh, von hier: http://www.c-plusplus.net/forum/317308-full

    Zweitens: Der gezeigte Code funktioniert gar nicht. Es funktioniert, wenn du es so umschreibst*:

    boost::dynamic_bitset<> generate(boost::dynamic_bitset<>::size_type n)
    { 
       const int bpb  = boost::dynamic_bitset<>::bits_per_block; 
    
       std::vector<boost::dynamic_bitset<>::block_type> arr(n%bpb ? n/bpb+1 : n/bpb);  // Siehe Link, lässt sich abkürzen
    
       static std::independent_bits_engine<std::minstd_rand, 
             boost::dynamic_bitset<>::bits_per_block, 
             boost::dynamic_bitset<>::block_width_type> engine; 
    
       std::generate(std::begin(arr), std::end(arr), engine); // Hmm. Vielleicht std::ref, gehts bei dir dann?
    
       boost::dynamic_bitset<> ret(std::begin(arr), std::end(arr)); 
       return ret; 
    }
    

    Und wenn du meinen mit deinem vergleichst, siehst du, dass ich seede.
    Mit std::generate hat das nichts zu tun - Schleifenversion und generate produzieren auf meinem Rechner gleiche Bits.

    static std::independent_bits_engine<std::minstd_rand,
                                           boost::dynamic_bitset<>::bits_per_block,
                                           boost::dynamic_bitset<>::block_width_type> engine( std::chrono::system_clock::now().time_since_epoch().count() ); // list-initialization mal weggelassen, führt hier zu narrowing
    

    *Edit: Ok, ja, du hast ein Klammerpaar vergessen, dann geht auch die Version aus deinem Post (du seedest). Allerdings selbes Ergebnis bei mir: Sowohl Schleife als auch generate bringen gleiche Ergebnisse. Es liegt nur am Seed.



  • Wie kann ich dann die std::random_device rd zum seeden benutzen?

    Wenn ich schreibe:

    static std::independent_bits_engine<std::minstd_rand,
                                           boost::dynamic_bitset<>::bits_per_block,
                                           boost::dynamic_bitset<>::block_width_type> engine{ rd };
    

    kompiliert VC++ 2010 nicht, die {} Klammern mag er nicht?



  • Ja, wenn ich std::ref nehme:

    std::generate(arr.begin(), arr.end(),std::ref(engine));
    

    Dann geht es. Aber wieso muss man an dieser Stelle std::ref verwenden?



  • Wie kann ich dann die std::random_device rd zum seeden benutzen?

    Das solltest du gar nicht. Nimm einfach meine Version. random_device ist auch laut Standard nicht verpflichtet, bei jedem Programmablauf neue Zahlen zu erzeugen.

    If implementation limitations prevent generating non-deterministic random numbers, the implementation may employ a random number engine.

    Die geschweiften Klammern sind ein C++11-feature, genannt list-initialization.



  • (Doppelpost)



  • Danke fuer die Hilfe und Hinweise! Aber warum geht es nur mit std::ref?



  • Random_1337 schrieb:

    Danke fuer die Hilfe und Hinweise! Aber warum geht es nur mit std::ref?

    Weil so nicht kopiert wird, das war eigentlich nur geraten von mir...



  • Sone schrieb:

    random_device ist auch laut Standard nicht verpflichtet, bei jedem Programmablauf neue Zahlen zu erzeugen.

    If implementation limitations prevent generating non-deterministic random numbers, the implementation may employ a random number engine.

    Zu beschreiben was daran Quark ist und wieso genau ist hoffentlich etwas was ich nicht tun muss, oder?



  • Random_1337 schrieb:

    Danke fuer die Hilfe und Hinweise! Aber warum geht es nur mit std::ref?

    std::generate nimmt den Generator "by value" - wie es in der STL mit Funktoren üblich ist. D.h. er wird kopiert, und dadurch bleibt das Original unverändert.


Anmelden zum Antworten