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()
undrand()
und nimm C++11-Zufallsgeneratoren. Damit kannst du auch gleich eine Verteilung erzeugen, die funktioniert. Mitrand()
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 dermain()
, 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 vonrand
verwendeten Generators ein.
Wenn du also srand(42) unmittelbar gefolgt vonrand()
machst, dann bekommst du bei diesemrand()
Aufruf immer die selbe Zahl (ausgenommen natürlich mit einer anderen C++ Implementierung - der vonrand()
verwendete Algorithmus ist soweit ich weiss nicht vom Standard vorgeschrieben).
Undtime(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 mehrrand()
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.
-
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.
-
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.