Schöne zufallszahlen



  • Hallo zusammen,

    ich suche einen Weg, wie ich schönere Zufallszahlen generieren kann. Ich habe hier ein Simulator, wo 10 Knoten beim Starten eine initiale Sequenznummer erzeugen sollen, leider "raten" alle die gleich. :(. Im Moment mache ich es so:

    srand(time(NULL));
    sequ = rand()%5000+1;
    

    Um einen Startwert zwischen 0 und 5000 zu bekommen. Die sequ ist vom Typ int. Wie gesagt, im Moment kommt da bei allen 10 das gleiche raus. Jemand nen Tip, wie ich es noch ein wenig zufälliger machen könnte???

    Grüße

    Sven



  • Vergiss srand() und rand() und nimm C++11-Zufallsgeneratoren. Damit kannst du auch gleich eine Verteilung erzeugen, die funktioniert. Mit rand() ist das nicht ganz trivial (% ist nämlich nicht richtig, auch wenn es in kleinen Szenarien zu funktionieren scheint).

    #include <random>
    
    std::mt19937 engine; // dein Zufallsgenerator
    std::uniform_int_distribution<int> distr(0, 5000); // deine Verteilung
    
    int r = distr(engine); // deine Zufallszahl
    

    Wenn du pro Durchlauf verschiedene Ergebnisse willst, kannst du den Zufallsgenerator seeden, zum Beispiel mit std::random_device .

    Weiteres siehe hier.



  • mh, schöne lösung. da muss ich allerdings erst mal mein admin fragen, ob er hier bei meiner centos 6 machine den gcc 4.7 installiert. im moment hab ich leider nur 4.4.7 und da kennt er die uniform_int_distribution nicht. aber erst mal vielen danke. muß ich morgen mal schauen, was da rauskommt. 🙂



  • Du rufst srand() mehr als einmal, richtig?



  • ja, jede instanz für sich. da sie hier im simulator laufen, wird es sozusagen mehrfach aufgerufen, damit wohl auch immer der gleiche seed. die frage ist, da ich im moment nicht die c++11 variante nehmen kann, ob man dies noch ein wenig hübscher machen kann, so dass ich nicht code einbauen muß, ob es die erste oder letzte instanz ist, welche hochgefahren wird.



  • Ruf srand() einmal am Anfang der main() , und gut is.



  • Und noch die Erklärung warum du mit srand(time(0)) + rand() 10x hintereinander die selben Zahlen bekommst...

    Mit srand stellst du den "Seed" (Ausgangszustand) des von rand verwendeten Generators ein.
    Wenn du also srand(42) unmittelbar gefolgt von rand() machst, dann bekommst du bei diesem rand() Aufruf immer die selbe Zahl (ausgenommen natürlich mit einer anderen C++ Implementierung - der von rand() verwendete Algorithmus ist soweit ich weiss nicht vom Standard vorgeschrieben).
    Und time(0) gibt dir die aktuelle Zeit, und zwar als Ganzzahl in Sekunden.

    Wenn du also in der selben Sekunde 10x time(0) aufrufst bekommst du 10x die selbe Zeit. Und wenn du 10x den selben Seed einstellst und dann eine Zahl ziehst, dann bekommst du eben 10x die selbe Zahl.

    => Nur 1x bei Programmstart seed(time(0)) machen, und danach nur mehr rand() aufrufen.

    EDIT: zu langsam.



  • @Nexus
    Die neuen Generatoren müssen auch geseedet werden.
    Sonst bekommt man einen (konstanten) Default-Seed, und damit immer die selbe Zahlenfolge.



  • sven_ schrieb:

    simulator

    Für ne Simulation solltest du wirklich bessere Generatoren verwenden als rand() .
    Die "neuen" C++ Generatoren gibt es schon lange als Bestandteil der Boost, und die sollte auf fast jedem Linux System vorhanden bzw. ohne Umstände als Paket nachinstallierbar sein.

    => http://www.boost.org/doc/libs/1_55_0/doc/html/boost_random.html



  • Hallo zusammen,

    nun, leider komme ich an die main nicht ran. So habe ich es nun so gemacht:

    //init the message reference counter
                std::mt19937 engine; // random generator
    #if ! OMNETPP
                std::uniform_int<int> distribution(0, 10000); //std::uniform_int_distribution<int>
    #else
                unsigned int offSet = module.getParentModule()->getIndex()+1;
                std::uniform_int<int> distribution(0, 1000 * offSet); //std::uniform_int_distribution<int>
    #endif
                sequ = distribution(engine);
    

    So tut es! Vielen dank! 😉



  • Sonst gäbe es Random auch noch im std::tr1 . Als ich allerdings letztes Mal (ein paar Jahre her) diese Implementierung unter g++ benutzt habe, war sie ziemlich verbuggt.

    @hustbaer: Ja, habe ich ja geschrieben 🙂
    Wenn man die Zeit zum Seeden nimmt, würde ich aber eine Uhr mit höherer Auflösung nehmen.


  • Mod

    Nexus schrieb:

    Wenn man die Zeit zum Seeden nimmt, würde ich aber eine Uhr mit höherer Auflösung nehmen.

    Tut clock() es nicht?



  • Nexus schrieb:

    @hustbaer: Ja, habe ich ja geschrieben 🙂
    Wenn man die Zeit zum Seeden nimmt, würde ich aber eine Uhr mit höherer Auflösung nehmen.

    Sorry, muss ich überlesen haben.


  • Mod

    Arcoth schrieb:

    Nexus schrieb:

    Wenn man die Zeit zum Seeden nimmt, würde ich aber eine Uhr mit höherer Auflösung nehmen.

    Tut clock() es nicht?

    Nein. Das gibt eventuell so etwas zurück wie die Zeit seit Programmstart. Was dann bei jedem Start zu einem Seed aus einem sehr kleinen Bereich führt.

    Ein paar gute Quellen für Seeds und weitere Gedanken zum Thema:
    -Einmal den Echtzufallsgenerator nach einem Seed befragen: Dies ist eine der besten Quellen. (Achtung: in gewissen Szenarien (z.B. kurz nach Systemstart) ist das eventuell auch nicht sehr zufällig).
    -Wenn's nicht kryptografisch sicher sein braucht, dann kann (und sollte) man den normalen PRNG benutzen, den praktissch jedes OS zur Verfügung stellt.
    -Wenn man keine Zufallszahlenquelle haben sollte: Die Uhrzeit zusammen mit der PID verhasht sollte einen halbwegs zufälligen Wert geben, wenn man das Programm nicht hundert tausende Male pro Sekunde startet. Der Fantasie sind hier kaum Grenzen gesetzt, z.B. kann man auch die Host-ID noch mit reinnehmen, wenn man auf einem Großrechner arbeitet.
    -Wenn man schnell viele Prozesse startet (zehntausende!), die miteinander kommunizieren können, dann kann man auch einen davon seeden und dessen Zahlen als Seed an die anderen Prozesse schicken.
    -Wenn man zehntausende Prozesse startet, dann sollte man auch da drauf achten, dass der Seed überhaupt genügend Entropie haben kann. Wenn man zehntausende 32-Bit Zahlen erzeugt, dann wird die Wahrscheinlichkeit, dass zwei davon gleich sind, schon recht groß (Geburtstagsparadoxon). Da sollte man schon mit 64 Bit recchnen.


Anmelden zum Antworten