Problem mit rand()



  • Ich hab ein etwas seltsames Problem mit der random funktion. Ich muss dazu sagen das ich c++ seit genau 2 wochen erst verwende. Trotzdem dachte ich eigentlich das ich alles richtig gemacht habe.

    Ich benötige öfter in meinem Programm eine zufallszahl. Nun habe ich mir also eine Funktion gemacht:

    int RandomInt(int min, int max)
    {
        srand(time(NULL)); 
        int random_integer; 
        int lowest=min, highest=max; 
        int range=(highest-lowest)+1;  
        random_integer = lowest+int(range*rand()/(RAND_MAX + 1.0)); 
        return random_integer;
    }
    

    Diese Funktion rufe ich dann immer wieder auf. Bei jedem Aufruf soll eine Zufallszahl zurückgegeben werden.

    Der Aufruf der Funktion:

    for (int index1 = 0; index1 < Stellenanz; index1++)
    {
    	myarrayA[index1] = IntToString(RandomInt(mymin, mymax));
    	cout << "Symbol "<< myarrayA[index1] << " wurde ausgewählt" <<endl;
    }
    

    Mein Problem jetzt an der Funktion: Wenn ich das Programm aufruf kommt dann immer die gleiche zahl. Und zwar so oft wie halt die for schleife durchlaufen wird.

    Auch wenn ich das ganze Prgramm 10x ausführ kommen immer die selben Zahlen.

    zu meinen 2 Fragen

    1. Wieso kommt da X mal die selbe Zahl?
    2. Wieso kommt sogar wenn ich das ganze Programm neu starte immer noch die selbe zahl?


  • Hallo

    srand darf nur einmal pro Programmaufruf, meistens ganz am Anfang, ausgeführt werden. Siehe auch den ausführlichen Artikel über Zufallszahlen in Forumsmagazin.

    bis bald
    akari



  • 1. srand(time(NULL)); nur einmal aufrufen. Am Start des Programms oder der Initialisierung der Zufallsklasse.

    2. In deiner Berechnung hast du ein paar Unsicherheiten, mach es lieber so:

    (static_cast<double>(rand())/static_cast<double>(RAND_MAX))*range + lowest
    

    Denn wenn RAND_MAX auch gleich MAX_INT ist und du eins dazu addierst, kann es zu einem Problem kommen. Ebenso das multiplizieren von range und rand() kann zu einem Überlauf führen.



  • danke gleich mal!
    Hab es jetzt am Anfang und es funktioniert soweit mal annehmbar.

    Nur aus neugierde noch: Auch hier fällt mir auf das die erste zufallszahl immer die gleiche ist. Bei jedem Programmaufruf. Die restlichen sind dann immer anders. Warum ist aber die 1. immer gleich?



  • abzy schrieb:

    Warum ist aber die 1. immer gleich?

    Wenn Du srand( ) wirklich nur einmal beim Programmstart aufrufst: Zufall 😃

    cheers, Swordfish



  • Ich weiß nicht ob dir das Prinzip der Pseudozufallszahlen bekannt ist, es läuft aber in etwa so:

    Du hast eine Kette bestimmter Zufallszahlen, immer die gleichen. Durch das srand springst du an eine bestimmte Stelle in der Kette. Hier an eine Stelle bestimmt durch time(NULL), also der aktuellen Zeit. Von da an geht rand() immer ein Stück weiter um die nächste Zahl zu bestimmten.

    Wenn du immer die gleiche Zahl bekommst, wird srand jedesmal aufgerufen.
    Wenn du immer die gleichen Zahlen bekommst, wird srand immer mit dem gleichen Parameter aufgerufen.
    Wenn du immer die gleiche Zahl als erstes bekommst ist das "Zufall". 😉



  • abzy schrieb:

    Warum ist aber die 1. immer gleich?

    Das ist schon sehr merkwürdig, Zufall ist das mit Sicherheit nicht. Ich hab den Code mal implementiert und mir die Zwischenvariabeln ausgeben lassen. Dabei hab ich herausgefunden, dass der erste rand()-Aufruf nach srand() immer eine ungefähr gleich grosse Zahl erzeugt - sofern es innerhalb kurzer Zeit passiert. Bei ähnlichem time(0) werden auch ähnliche erste Werte erzeugt - das ist vom Algorithmus des Linearen Kongruenzgenerators (Art des rand()-Generators) her gegeben. Diese Tatsache erscheint für mich als guter Grund, den eingebauten Zufallsgenerator zu vermeiden. Wenn jener Algorithmus so aufgebaut ist, dass trotz unterschiedlichem Startwert immer ein ähnlicher erster Zufallswert entsteht, sind für mich die Anforderungen an einen guten Zufallsgenerator (v.a. gute Verteilung der Zufallszahlen) nicht erfüllt. Klar kann man immer zuerst einige Male rand() aufrufen. Meistens spielt das praktisch sowieso nicht so eine grosse Rolle, da die Zufallszahl sich doch jedesmal leicht unterscheidet und dies bei der Modulo-Operation mit kleinen Zahlen zu unterschiedlichen Zufallszahlen führt. Dennoch... 🙄

    Doch nun zum Problem^^
    Dadurch ist in deinem Programm rangerand()* beim ersten Mal immer ungefähr gleich gross. Die Integer-Division durch die Konstante (RAND_MAX + 1) führt dazu, dass folgender Ausdruck beim ersten Aufruf von rand() fast immer gleich ist (wird ja abgerundet):

    range*rand()/(RAND_MAX + 1.0)
    

    So ist auch deine erste Zufallszahl fast immer gleich.

    Ich hätte nicht gedacht, dass der rand()-Generator solche Mängel aufweist, gut, dass ich darauf hingewiesen wurde - in Zukunft werde ich aus Misstrauen wohl meinen eigenen Generator basteln 😃



  • So, ein paar Tage sind vergangen und ich hab brav weiter an meinem Programm geschrieben. Sonntag ist letzter Abgabe Termin. Genau deswegen bin ich sicherheitshalber heute nochmal an die Uni gefahren um hier mein Programm auf den Linux Rechnern zu kompilieren und testen.

    Mal abgesehen von kleinen Zeichen Fehlern gibt es aber ein ganz gravierendes Problem auf einmal.

    Hier unter Linux kommen auf einmal keine Zufallszahlen mehr. Zuerst dachte ich mir das srand() bzw rand() vl nicht unter Linux funktionieren, aber irgendwo im Netz hab ich dann irgendwas gefunden das gesagt hat das es doch funktioniert.

    Jetzt meine Frage an euch: Die CodeZeilen oben sind noch immer 1:1 genau so wie jetzt gerade, Mit der Ausnahme das srand(time(0)) jetzt gleich ganz oben am Start der Main aufgerufen wird und dann nie wieder.

    Dazu möchte ich nochmal sagen: Unter Windows hat es Problemlos funktioniert. Hier unter Linux (auf den Uni Rechnern) funktioniert es überhaupt nicht. Ich bekomme außer 1er nur 1er und nochmal 1er. 😞

    Hoffe ihr könnt mir nochmal helfen das zu lösen

    LG
    Daniel



  • Zur Sicherheit alle Relevanten Code Zeilen nochnmal:

    ...code...
    int RandomInt(int min, int max);
    
    int main(int argc, char *argv[])
    {
    	...(code)...
    	srand((unsigned)time(0));
    	...(code)...
            myarrayA[index1] = IntToString(RandomInt(mymin, mymax));
            ...(code)...
    }
    ...code...
    int RandomInt(int min, int max)
    {
    
        int random_integer; 
        int lowest=min, highest=max; 
        int range=(highest-lowest)+1;
        random_integer = lowest+(int)(range*rand()/(RAND_MAX + 1.0)); 
        cout <<"Min: "<< lowest << " Max! :" << highest << endl;
        return random_integer;
    }
    

    Ok, ich hab mir jetzt mal die Ergebnisse von der rand() Funktion direkt ausgeben lassen:

    1033223895, 
    1154161622, 
    1032961076, 
    669149932, 
    1292121368, 
    1316851777, 
    76798912, 
    1988176058, 
    870162788, 
    147684079, 
    1713094073, 
    56935561, 
    2130274594
    

    Wie man erkennt sind es tatsächlich irgendwelche Zahlen. Was ich damit sagen will: Scheinbar muss der Fehler in genau der Zeile sein:

    random_integer = lowest+(int)((range*rand())/(RAND_MAX + 1));
    

    rand() liefert gute Werte.
    range hat richtige Werte.
    RAND_MAX hat den Wert 2147483647.

    Trotzdem kommt IMMER 1 dann in random_integer. Warum?



  • 1 => 1.0
    

    Trotzdem ist es besser zuerst zu dividieren, da es sonst schnell mal zu einem Überlauf kommen kann (man hat plötzlich negative Werte).

    Gruß
    Don06


Log in to reply