Prüfung von zufallszahlen benötigt viele Versuche



  • Hallo zusammen,

    ich muss 6 Zufallszahl innerhalb eines bestimmten Bereiches generieren.
    Die Bereichsgrenzen sind min- und max-Werte von Arrays. Die Bereiche der Arrays decken aber nicht den Gesamtbereich ab.
    Beispiel:

    int sfo[anz_sfo] = {6001, 6180, 6200, 6399};
    

    Das sind 2 Bereiche: 6001 - 6180 und 6200 - 6399.
    Die Zufallszahl ermittle ich also durch

    agnr_min=MinIntValue(sfo, anz_sfo-1); //Ermitteln von min-Wert; hier: 6001        
    agnr_max=MaxIntValue(sfo, anz_sfo-1);       //Ermitteln von max-Wert; hier: 6399
    randomize();
    ag[arr_pos]=random(max_wert-min_wert+1)+min_wert;
    

    Der Wert arr_pos in ag[arr_pos] legt die Position des Arrays fest, das die 6 Zufallszahlen aufnimmt (Das Ganze ist in einer Schleife).

    Jede Zufallszahl vergleiche ich mit den bereits ermittelten, damit keine doppelt ist.
    Anschliessend prüfe ich sie, ob sie in Bereiche passt.
    Beispiel: Die Zahl 6190 muss durchfallen, weil sie nicht in die Bereiche 6001 - 6180 und 6200 - 6399 passt.
    Ich prüfe das ganz normal mit >= und <= etc.

    Mein Problem ist folgendes:
    Zum Ermitteln der 6 Zahlen braucht das Programm ca. 5 Sekunden.
    Setze ich Haltepunkte an den Stellen, an denen die Prüfroutinen verlassen werden weil die Zufallszahl nicht den Kriterien entspricht, bin ich durch Drücken der F9-Taste gleich schnell.
    Ich hab nun an diesen Stellen Zähler angebracht um festzustellen, wie oft die Routinen auf diesen Wegen verlassen werden.
    Drücke ich F9 beim Erreichen eines Haltepunktes, ist es ca. 10 - 15 Mal.
    Lasse ich die F9-Taste permanent gedrückt, sind es ca. 100 - 150 Mal.
    Läuft das Programm normal durch, bis zu 3,5 Millionen mal.

    Woher kommt das ? Es muss anscheinend mit einem Zeitfaktor zusammen hängen.
    Wer hier was weiß bitte melden !!

    Vielen Dank
    Gruß Markus



  • Markus Pelloth schrieb:

    Jede Zufallszahl vergleiche ich mit den bereits ermittelten, damit keine doppelt ist.
    Anschliessend prüfe ich sie, ob sie in Bereiche passt.

    Mach das umgekehrt.

    Wie prüfst Du ob die Zahl schon vorhanden ist? mit std:find() und co.?
    Wenn die Definitionsbereiche nicht groß sind, dann würde ich ein Bit-Array (TBit ist evtl. zu langsam?) anlegen und für jede Zahl ein Flag setzen.

    Wird bei Dir randomize() jedes mal in der Schleife aufgerufen? Ein mal sollte reichen.



  • ich kenn mich mit dem borlandbuilder gar nicht aus aber kann man da nicht auch die stl verwenden?...
    wenn ja würd ich einfach ein set nehmen und da immer zufallswertereinpacken bis eine vorher angegebene anzahl von werten im set erreicht ist... damit muss man sich dann nicht mehr selber den aufwand machen zu ermitteln obs den wert schon einmal gibt...



  • Markus,
    zwei Dinge:

    1. Wie bIce schon angedeutet hat, rufst Du randomize() vermutlich jedesmal neu auf. "Zufallszahlen" werden aus einer Zahlenfolge mit sehr hoher Periode (2 hoch 32 oder so) entnommen. Allerdings wird diese durch die aktuelle System-Zeit (bei Sekunden-Genauigkeit) initialisiert. D.h., daß Du ca. eine Sekunde lang immer wieder mit dem selben Zufalls-Wert beginnst, wenn Du ständig randomize aufrufst. Das drückt die Performance gewaltig und bring diese seltsamen Zeiteffekte hervor.

    Markus Pelloth schrieb:

    Beispiel: Die Zahl 6190 muss durchfallen, weil sie nicht in die Bereiche 6001 - 6180 und 6200 - 6399 passt.
    Ich prüfe das ganz normal mit >= und <= etc.

    Die Prüfung könntest Du umgehen:

    int diff = 6180 - 6001;  //=179
    int z = 6001 + random(diff + 1);    //=6001 + [0..179]
    


  • Hallo Leute,

    ihr seid echt Spitze !! Jetzt gehts so, wie es soll.
    Randomize ist bei jedem Schleifendurchlauf aufgerufen worden. Jetzt weiß ich das auch 🙂

    @bIce:
    Ich prüfe, ob die Zahl schon vorhanden ist, so:

    int pruef_1=0;                               
    for(pruef_1; pruef_1<arr_pos; pruef_1++)  //an arr_pos ist die aktuelle Zufallszahl
            {
            if(arr_wert==ag[pruef_1])   //prüft jeden Array-Eintrag
            return false;
            }
    return true;
    

    Ich vergleiche den aktuellen Eintrag des Arrays, das die Zufallszahlen aufnimmt, mit den bereits vorhandenen Werten.
    Ich denke, dass das schneller geht. Die Prüfung der Bereiche dauert länger, da es am Ende mehr sind. Zur Entwicklung hab ich jetzt mal 2 genommen.
    Grundsätzlich ist die Anzahl unterschiedlich.

    @dschenskyQ
    Wenn ich das wie von Dir vorgeschlagen mache:

    int diff = 6180 - 6001;  //=179
    int z = 6001 + random(diff + 1);    //=6001 + [0..179]
    

    Dann krieg ich aber eine Zufallszahl zwischen 6001 und 6180.
    Ich brauche aber eine zwischen 6001 und 6180 ODER 6200 und 6399.
    Anders gesagt: Ich brauche eine zwischen 6001 und 6399, die aber nur zwischen 6001 und 6180 oder 6200 und 6399 passen muss.
    Ich weiß, das ist ungut, aber das sind gewachsene Strukturen. Die kann ich nicht so einfach aufbrechen.
    Ich bin am Überlegen, ob ich das nicht so mache:

    Ich habe jetzt schon ein Array, das alle Grenzwerte aufnimmt. Die ersten 4 sind "belegt", in diesem Fall mit 6001, 6180, 6200, 6399. Es sind 12 Werte vorgesehen. Der Rest ist auf "0".
    Ich kann die Prüfung jetzt so vornehmen:

    if((testwert <= Array[0] && testwert >= Array[1]) || (testwert <=Array[2] && testwert >= Array[3]) usw.
    

    Dann spar ich mir die Schleifendurchläufe, habe dafür immer alle Einträge zu vergleichen. Ich weiss nicht was kürzer ist. Ich denke aber, die Schleife.

    Wie auch immer, es funktioniert momentan super, und das ist das wichtigste !!

    Danke nochmal.

    Gruß Markus



  • Noch ein Tip:

    Du kannst ja auch

    int totalRange = (6180-6001+1) + (6399-6200+1);

    int value = (rand() % totalRange) + 6001;
    if (value > 6180)
    value += (6200-6180+1);

    (natürlich schön mit konstantendefinitionen verzieren und +/-1 - Fehler rausschmeißen 😉

    aber das lohnt sich für 6 Zahlen wahrscheinlich schon gar nicht mehr...



  • Markus,

    Markus Pelloth schrieb:

    zwische 6001 und 6180 ODER 6200 und 6399.

    dann setz Dich mal hin und grüble ein wenig. Da fällt Dir dann bestimmt was ein.
    Tipp: random(2) liefert auch einen Zufallswert: 0 ODER 1



  • Hallo Dschensky,

    jetzt check ich das ! Die Idee ist ja super.
    Ich ermittle erst mit einer Zufallszahl den Bereich und generiere dann eine Zufallszahl für diesen. Dann spar ich die ganzen Prüfroutinen.

    Tja, es bleibt dabei: Die meisten wirklich brauchbaren Tipps kriegt man tatsächlich in diesem Forum.

    Wenn Du willst, post ich den Code wenn ich fertig bin 🙂

    Gruß Markus



  • Markus Pelloth schrieb:

    Tja, es bleibt dabei: Die meisten wirklich brauchbaren Tipps kriegt man tatsächlich in diesem Forum.

    Und das Forum ist stolz auf Dich - wegen Selberdenken! 🙂

    Markus Pelloth schrieb:

    Wenn Du willst, post ich den Code wenn ich fertig bin 🙂

    Das ist Deine Entscheidung...

    ...die Netiquette schrieb:

    Teilen Sie etwas Neues mit!



  • In Anbetracht der Netiquette:

    int wert=0;
    wert = random(anz_sfo/2-1)*2;    //anz_sfo ist die anzahl der Array-Einträge
    ag[i] =  random(sfo[wert+1]-sfo[wert])+sfo[wert];    //sfo[] ist das Array selbst
    

    Funktioniert einwandfrei.



  • Nur ein kleiner Hinweis: wenn die Abschnitte nicht gleich groß sind, dann sind die Zufallszahlen nicht gleichmäßig über alle möglichen verteilt (d.h. eine Zahl aus einem kurzen Intervall hat eine größere Chance als eine Zahl aus einem langen Intervall)

    Kommt aber auf die Anwendung drauf an, ob das ein Problem ist (sonst meinen vorherigen Post nochmal versuchen zu entschlüsseln 🤡 )



  • Das ist richtig, spielt aber keine Rolle. Ich pick mir von den 6 Zahlen dann manuell eine per Button-Klick raus. Geht leider nicht anders. Die, die ich mir rauspicke kommt in ne Liste. Jede Zufallszahl wird auch mit dieser Liste verglichen, da jede nur 1 Mal drankommen darf. In welchem Bereich das ist, is zum Glück wurscht.


Anmelden zum Antworten