keine doppelten zahlen bei rand()



  • Und das %Obergrenze+Untergrenze; funktioniert nur bei Untergrenze = 1 richtig.
    Dann kannst du die 1 auch direkt hinschreiben.

    Das 1 + (rand() % 50); von Bitmapper ergibt Zahlen von 1 bis 50 (einschließlich).



  • Habs korrigiert

    1 + (rand() % 49)
    


  • Nur mal so noch nebenbei, die erste For-Schleife ist nicht nötig ^^, wenn du bei der Array definition das erste Elemente mit 0 deklarierst, bekommen sämtliche anderen Elemente des Array ebenfalls 0 😉



  • Ich finde die Variante mit einem shuffle auch schick (wenngleich für 6/49 nicht gerade Laufzeitoptimal):

    initialisiere ein Array mit 1...49
    für alle i Elemente in Array
       tausche Element i mit zufälligem Element in Array
    Nimm die ersten 6 Werte aus Array
    

  • Mod

    Der echte Tim schrieb:

    Ich finde die Variante mit einem shuffle auch schick (wenngleich für 6/49 nicht gerade Laufzeitoptimal):

    initialisiere ein Array mit 1...49
    für alle i Elemente in Array
       tausche Element i mit zufälligem Element in Array
    Nimm die ersten 6 Werte aus Array
    

    Das ist weder effizient (wie du selber feststellst), noch überhaupt korrekt. Dein Shuffle ist biased und produziert gewisse Folgen häufiger als andere. Probier es mal auf Papier mit 3 Elementen aus.

    Ein Fisher-Yates hätte hier folgende Vorteile gegenüber deinem und allen anderen Vorschlägen:
    a) Es ist nicht komplizierter als die anderen Vorschläge, eher im Gegenteil. Im Vergleich zu deinem Vorschlag ist es beispielsweise nur eine minimale Änderung.
    b) Es ist extrem effizient, da man einfach nach den ersten 6 Zahlen aufhören kann
    c) Wegen b ist es auch für andere Probleme gut geeignet. Wie zum Beispiel "ziehe 48 aus 49", bei dem der Algorithmus mit dem Vergleichen einknicken würde. Mein Vorschlag ist vielleicht nicht immer der beste, aber er ist immer ganz ok, da er keine Schwächen hat.

    Also konkret:
    -Fülle Array mit Werten 1-49
    -Ziehe Index 0-48, tausche Array[index] mit Array[0]
    -Ziehe Index 1-48, tausche Array[index] mit Array[1]
    ...
    -Ziehe Index 6-48, tausche Array[index] mit Array[6]
    -Die Werte in Array[0] bis Array[6] sind nun eine zufällige Sequenz von Werten aus dem Array

    PS: Eine andere Schwäche aller Vorschläge hier (inklusive meinem) ist, dass der Zufallsgenerator eventuell einfach nicht gut genug ist. Bei einigen alten Implementierungen (MSVC 6 und älter) ist die Periodenlänge von rand so um die 16 Millionen. Das ist von der gleichen Größenordnung wie die Zahl der Kombinationen von 6 aus 49 (13 Millionen). Das heißt, gewisse Kombinationen zieht man damit auch gerne mal doppelt so oft wie andere, eventuell zieht man manche sogar nie. Man sollte also vielleicht was eigenes implementieren, anstatt zu hoffen, dass rand vernünftig implementiert ist. Die üblichsten Implementierungen haben nämlich auch nur Perioden von 2^31 bis 2^31, was nun auch nicht gerade extrem viel mehr als 13 Millionen ist.



  • SeppJ schrieb:

    Das ist weder effizient (wie du selber feststellst), noch überhaupt korrekt. Dein Shuffle ist biased und produziert gewisse Folgen häufiger als andere. Probier es mal auf Papier mit 3 Elementen aus.

    Dann finde ich das nicht mehr schick sondern sogar ausgesprochen scheisse.



  • SeppJ schrieb:

    Bei einigen alten Implementierungen (MSVC 6 und älter) ist die Periodenlänge von rand so um die 16 Millionen. Das ist von der gleichen Größenordnung wie die Zahl der Kombinationen von 6 aus 49 (13 Millionen). Das heißt, gewisse Kombinationen zieht man damit auch gerne mal doppelt so oft wie andere, eventuell zieht man manche sogar nie. Man sollte also vielleicht was eigenes implementieren, anstatt zu hoffen, dass rand vernünftig implementiert ist. Die üblichsten Implementierungen haben nämlich auch nur Perioden von 2^31 bis 2^31, was nun auch nicht gerade extrem viel mehr als 13 Millionen ist.

    Man müßte schon sauviel Pech haben, daß die Periode des Programms mit der Periode des Zufallszahlengenerators einen großen gemeinsamen Teiler hat.



  • ich vermute momentan, dass das Problem wohl doch woanders liegt, aber den Fehler im Programm finde ich einfach nicht. Wäre cool wenn der ein oder Andere mir da weiterhelfen könnte 😃

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <stdbool.h>
    
        double fak (double n){ //Unterfunktion Fakultät
            if(n == 0){
    		return 1;
            }
                else{
        	return n*fak(n-1);
            }
        }
    
    int main(void) {
    
        int Untergrenze = 1;
        int Obergrenze = 49;
        int ziehung = 6;
    
        int sortierung1;
        int sortierung2;
        int zufallszahl;
        double binom = 1;
    
        int i;
        int k;
        int m = 0;
    
        int eingabe[6];
        int Lottozahlen[6];
        int treffer[6];
    
        srand(time(NULL));
    
        printf("Geben Sie bitte 6 Zahlen von 1 - 49 ein um an der Lotterieziehung teilzunehmen.");
    
        for(i=0; i<ziehung; i++) {
            printf("\n\nZahleneingabe: ");
            scanf("%d",&eingabe[i]);
    
            while (eingabe[i]<1) {
            printf("\n\nIhre Eingabe ist kleiner als zulaessig.");
            printf("\nWiederholen Sie die Zahleneingabe. ");
            printf("\n\nZahleneingabe: ");
            scanf("%d",&eingabe[i]);
            }
            while (eingabe[i]>49) {
            printf("\n\nIhre Eingabe ist groesser als zulaessig.");
            printf("\nWiederholen Sie die Zahleneingabe. ");
            printf("\n\nZahleneingabe: ");
            scanf("%d",&eingabe[i]);
            }
        } //Ende FOR-Schleife für Eingabe
    
        printf("\n\nIhre ausgewaehlten Lottozahlen lauten: \n\n");
        printf("1.Auswahl: %d\n",eingabe[0]);
        printf("2.Auswahl: %d\n",eingabe[1]);
        printf("3.Auswahl: %d\n",eingabe[2]);
        printf("4.Auswahl: %d\n",eingabe[3]);
        printf("5.Auswahl: %d\n",eingabe[4]);
        printf("6.Auswahl: %d\n",eingabe[5]);
    
    while (m<3) {
    
            printf("\n\nDie momentanen Lottozahlen lauten: \n\n");
    
            for (i=0; i<ziehung; i++) {
                Lottozahlen[i] = 0;
            }
    
            for (i=0; i<ziehung; i++) {
    
                zufallszahl = 1 + (rand() % 49);
                Lottozahlen[i] = zufallszahl;
    
                if(i>0) {
    
                        if (Lottozahlen[i-1]==Lottozahlen[i]) {
                                Lottozahlen[i] = Lottozahlen[i] +1;
                        }
                }
    
                 if (Lottozahlen[i-1]=Lottozahlen[i]) {
                                Lottozahlen[i] = Lottozahlen[i] +1;
                }
    
            } // Ende FOR-Schleife für Sortierung der Lottozahlen
    
      }
    
                        for(k=0; k<ziehung; k++) {
                                //printf("I: %d\n",i);
                                for(i=0; i<ziehung; i++) {
                                    //printf("K: %d\n",k);
                                    if(eingabe[k]==Lottozahlen[i]) {
                                        treffer[m]=eingabe[k];
                                        m++;
                                    }
                                }
    
                                if(m<3) {
                                    m=0;
                                }
                        }
    
        		//}
    
                for(i=0; i<ziehung; i++){ //Zufallszahlen ausgeben
                    printf("%d.Lottozahl: %d\n",i+1,Lottozahlen[i]);
                }
    
            if (m>2) {
                printf("\nGlueckwunsch, Sie haben %d Zahlen getroffen.\n",m);
                printf("Die folgenden Zahlen sind richtig: ");
                for(i=0;i<m;i++){ //Ausgabe aller richtig getroffenen Zahlen
                            printf("%d ",treffer[i]);
                }
            }
    
    } //Ende While schleife
    
            binom = fak(49)/(fak(6)*fak(43)); //Binomialkoeffizienten berechnen
            printf("\n\nDie Anzahl der moeglichen Ziehungen: %.0lf\n\n", binom);
    
            return 0;
    
    }
    

  • Mod

    Was ist denn überhaupt das Problem? Du schreibst bloß es "funktioniert nicht". Das ist keine Problembeschreibung anhand derer sich irgendjemand mal eben 200 Zeilen Quelltext ansehen wird.



  • Also es handelt sich um ein Programm für die Lottoziehung. Es werden 6 Zahlen von 1-49 eingegeben. Diese werden dann immer mit der zufälligen Zahlenziehung überprüft bis mindestens drei Zahlen übereinstimmen.

    Es müssen bei jeder zufälligen Zahlenziehung unterschiedliche Zahlen kommen, sprich keine doppelten Zahlen bei der momentanen Ziehung. Bei der nächsten Ziehung kann die ein oder andere Zahl ruhig wieder auftauchen solange sie in dieser ziehung nicht zwei oder drei mal auftaucht.

    In meinem Programm jedoch hab ich das Problem, dass das Programm halt paar Sekunden abläuft und mir dann einfach mal in der letzten Ziehung mindestens 3 gleiche Zahlen in der momentanen Ziehung anzeigt.

    Wenn in der momentanen Ziehung zB. eine 3 vorkommt dann darf sie für die nächsten 5 Zahlen nicht wieder vorkommen, sondern erst bei der nächsten Ziehung-


  • Mod

    Wenn das immer noch das Problem ist, dann lies den Thread noch einmal. Die erste Antwort und alles was danach kam, gelten immer noch:

    Furble Wurble schrieb:

    Vielleicht ist Dein Algorithmus um Dubletten festzustellen nicht richtig?

    Wobei man nun das "vielleicht" in der Antwort streichen kann. Denn das hier ist ganz sicher falsch:

    for (i=0; i<ziehung; i++) {
    
                zufallszahl = 1 + (rand() % 49);
                Lottozahlen[i] = zufallszahl;
    
                if(i>0) {
    
                        if (Lottozahlen[i-1]==Lottozahlen[i]) {
                                Lottozahlen[i] = Lottozahlen[i] +1;
                        }
                }
    
                 if (Lottozahlen[i-1]=Lottozahlen[i]) {
                                Lottozahlen[i] = Lottozahlen[i] +1;
                }
    

    Sowohl die Idee (Du vergleichst nur mit dem Vorgänger) als auch die Umsetzung (Was ist bei der ersten Zahl? Du scheinst diesen Fall bedacht zu haben, aber irgendwie auch wieder nicht) und sogar die grundlegende Syntax ('=' ist kein Vergleich!) sind falsch.

    Es wurden reichlich Anregungen in diesem Thread gegeben, wie du selber eine korrekte Prüfung durchführen kannst oder welche alternativen Verfahren geeignet sein könnten, die ganz ohne Prüfung auskommen.



  • genau diese Stelle war auch der Auslöser weshalb ich den Beitrag verfasst habe. Ich habe es mit Tipps die mir zuvor genannt wurden versucht, aber ohne Erfolg es wird trotzdem weiterhin noch bei der letzten Ziehung drei mal die gleiche Zahl gezogen.



  • Du hast da ohne viel Nachdenken hin und her geändert, ohne das eigentliche Problem zu beseitigen.

    Du musst die neue Zahl mit allen bisher gezogenen vergleichen.
    (Ja, das erfordert eine eigene Schleife)

    Bitmapper hatte schon einen Lösungsansatz gepostet: Die Nutzung von Funktionen.

    Und schau dir die Warnungen vom Compiler an. Aktiviere eine hohe Warnstufe, dann passieren solche Fehler wie eine Zuweisung beim if nicht.



  • 1. In deinem Code ist ungefähr jede 3. Zeile falsch, wirf ihn weg und fang von vorne an.
    2. Deine Klammersetzung ist Katastrophal setze jede! Klammer in eine extra Zeile und nur so viele wie nötig.
    3. Nicht nur der Code an sich ist falsch du überprüfst z.B. nicht ob der Benutzer mehrmals die selbe Zahl eingibt und du hast eine Endlosschleife drin, weil du m in jedem Durchlauf der for-Schleife 0 setzt.

    Meine Funktion kannst du übrigens 1 zu 1 in dein Programm übernehen.

    Als Alternative kann ich dir auch die Lösung schicken, das kostet dich dann aber was.



  • Nein danke! Ich hab es vorhin geschafft hab es an zwei Stellen verändert und nun läuft es einwandfrei 😃


Anmelden zum Antworten