Lottozahlen ohne Wiederholung



  • @TGGC sagte in Lottozahlen ohne Wiederholung:

    Noch besser ist übrigens einfach nur gezogenen Zahlen ans Ende (oder auch Anfang) des Arrays a zu swappen und das result Array komplett wegzulassen.

    Oh ja, das stimmt allerdings.


  • Mod

    Endlosschleifen mit if ... break als Kontrollelement. Benutzung von Zählvariablen nach Abschluss einer Schleife. Findest du das wirklich gut? Vielleicht solltest du noch einmal Abstand nehmen und nicht versuchen, deinen jetzigen Ansatz zu reparieren, sondern in Ruhe einen schönen Ansatz zu finden.

    Dein Programm besteht derzeit aus einer Reihe von Fehlerkorrekturalgorithmen für den jeweils davor liegenden Algorithmus. Zerlege das Problem in kleinere Unterprobleme, und finde einfache, korrekte Lösungen für diese Probleme. Dann setz diese Lösungen zusammen. Wutzs Programm hat nicht deshalb 10 Zeilen, weil er Zuweisungen in Funktionsaufrufen macht (ok, ein bisschen trägt das schon bei, aber nicht alles), sondern weil er effiziente Teillösungen effizient zusammen gebaut hat.



  • @Jockelx sagte in Lottozahlen ohne Wiederholung:

    Hallo,

    typischer Algorithmus für Lottozahlen ziehen ist:

    
    Array a mit Zahlen 1 bis 49
    for i=0 bis 5
    {
      x = rand(49-i)
      result[i] = a[x];
      swap(a[x], a[49-i]); // gezogene Zahl aus dem rand-Bereich raus nehmen
    }
    
    

    Ist auch genau meine Vorgehensweise, wenn ich irgendeine zufällige Reihenfolge von sich nicht wiederholenden Zahlen brauche, egal ob man aus einem Set von Zahlen alle braucht, oder nur ein paar ( 6 aus 49 ). Verschachtelte Schleifen sind überhaupt nicht notwendig.
    Das schöne an dem Algorithmus ist auch, dass allein das Array bestimmt, welche Zahlen verwendet werden. Die müssen auch gar nicht fortlaufend sein. Deswegen ist der Algorithmus auch so vielseitig.



  • Warum orientierst du dich nicht am "Original?"

    Du hast 49 Kugeln von 1 bis 49. Also ein Array von 0 bis 48.
    Dieses Array initialisierst du mit Zahlen von 1 bis 49.

    Dann generierst du eine Zufallszahl von 0 bis 48.
    Du streichst diese Zahl aus dem Array, in dem du das diese Zahl daraus löscht.
    Stell dir das so vor, wie wenn du aus einem Stapel Bücher eins raus nimmst.
    Beispiel:
    generierte Zufallszahl: 45
    Array vor dem Streichen: ...........42,43,44,45,46,47,48,49
    Nach dem Streichen...................42,43,44,46,47,48,49

    Da jetzt aber di Anzahl deiner Kugeln(Elemente) jetzt 48 sind.
    generierst du jetzt eine Z-Zahl von 0 bis 47
    dann wieder kürzen, dann ne Z-Zahl von 0 bis 46
    Bis du deine Zahlen hast.

    Das ganze machst du also 6 mal, mit Zusatzzahl 7 mal.
    In einem zweitzen Array legtst du dann deine generierten Zahlen ab.
    Beispiel:

    /***-----
    | getrand.c
    |
    | Demonstrates how to generate a random| number between 1 and a given value.
    |
    | NOTE: In real use, you would not want| to call srand() before every call to
    | rand(), because if you call rand()| quickly in succession, it will keep
    | returning the same results. Instead,| move the call to srand to the beginning
    | of your program and only call it once. It works in this program, but only
    | because getrand() is called a single| time.
    -----***/
    
    #include  <stdlib.h>
    #include  <stdio.h>
    #include  <time.h>
    
    int initrandom = 0;
    //generiert Zufallszahlen von 1 bis 32767;
    int getrand (int lowerlimit, int toprange)
    {
    // bis 32767
     //srand (time (NULL));
     if (initrandom == 0)
      {
      srand (time (NULL));
      initrandom = 1;
      }
     return (rand () % toprange) + lowerlimit;
    }
    
    void zeigezahlen(int zuzaar[], int zuzalimit)
    {
    int zeize = 0, slei;
    printf("\nZufallszahlen von 1 bis %d:\n", zuzalimit);
    
     for (slei = 0; slei < zuzalimit; slei++)
      {
      printf ("Nr.%d = %d  ", slei, zuzaar[slei]);
      zeize++;
      if (zeize >= 6) { printf("\n"); zeize = 0; }
      }
    }
    
    void initarreale(int obergrenze, int (*zuzaar)[], int (*schluessel)[], int (*wuerfel)[])
    {
    int slei;
    if (obergrenze > 89) obergrenze = 89;
    
     for (slei = 0; slei < 99; slei++)
       (*wuerfel)[slei] = 0;
    
     for (slei = 0; slei < obergrenze; slei++)
      {
       (*zuzaar)[slei] = 0;
       (*wuerfel)[slei] = slei;
       (*schluessel)[slei] = 0;
      }
    
    }
    
    void kuerzearreal(int zuza, int og, int wuerfel[], int (*schluessel)[], int stelle)
    {
    int slei;
    
    (*schluessel)[stelle] = wuerfel[zuza];
    for (slei = zuza; slei < og; slei++)
     {
        wuerfel[slei] = wuerfel [slei + 1];
     }
    printf("\nog: %d zuza: %d  stelle:%d   nach Kuerzung:   ", og, zuza, stelle);
    for (slei = 0; slei < (og - 1); slei++)
     printf(" -%d- ", wuerfel[slei]);
    }
    
    int main (void)
    {
     int untergrenze, toprange = 49, slei, wohin, dmog, sleia;
     int zuzaar[100], schluessel[100], wuerfel[100];
    
    untergrenze = 0;
    
    hauptmenue:
    printf("\nZufallszahlengenerator");
    printf("\nEnde...0   Obergrenze eingeben...1   Zahlen generieren...2");
    
    wouhi: printf("\nIhre Wahl: ");
        scanf("%d", &wohin);
        if (wohin == 0 ) goto finito;
        if (wohin == 1 ) goto setzeog;
        if (wohin == 2 ) goto genzuza;
      goto wouhi;
    
    setzeog: printf("\nObergrenze: (max 90)");
             scanf("%d", &toprange);
      goto hauptmenue;
    
    genzuza: if (toprange > 89) toprange = 89;
        initarreale(toprange, &zuzaar, &schluessel, &wuerfel);
    /*
         for (slei = 0; slei < 99; slei++)
          {
           zuzaar[slei] = slei;
          // wuerfel[slei] = schluessel[slei] = 0;
          }
    */
          zeigezahlen(zuzaar, toprange);
          zeigezahlen(schluessel, toprange);
          zeigezahlen(wuerfel, (toprange + 3));
          dmog = toprange;
          sleia = 0;
    
          for (slei = 0; slei < toprange; slei++)
           {
            zuzaar[slei] = getrand(untergrenze, dmog);
            kuerzearreal(zuzaar[slei], toprange, wuerfel, &schluessel, sleia);
            sleia++;
            dmog--;
            if (dmog == 0 ) goto fertig;
           }
    fertig:
    /*Generierte Zufallszahlen zeigen */
     zeigezahlen(zuzaar, toprange);
     zeigezahlen(schluessel, toprange);
    
     goto hauptmenue;
    
     finito: printf("\nProgrammende");
     return 0;
    }
    
    Hab mal ein Verschlüsselungsproggi geschrieben, das die Bit-Folgen von Dateien quasi durcheinander wirbelt.
    Da wird zuerst ein Array von 0 bis 131071 erstellt(=16384Bit) und mit 0 bis 131071 initialisiert. Jede Zahl darf nur einmal vorkommen. Diese Zahlen werden dann permutiert. Rein theoretisch gibt es dann 131071! (Faktorielle) Möglichkeiten, wie der Schlüssel dann aussieht.
    
    Genauer genommen ist das wegen dem mehrfachen Vorkommen einzelner Elemente innerhalb einer Klasse lauf Euler
     Verschlüsselungstiefe = { (16384+16384)! /(16384! *16384!)}
    Aber nur bei Gleichverteilung der gesetzten zu den ungesetzten Bits.
    Kannst ja mal nach Talarius googlen. 
    Deshalb habe ich diese Vorgehensweise entwickeln müssen, da die Zeit beim erstellen der Schlüsseldatei exponentiell
    ansteigt. Aber das würde jetzt zu weit gehen.
    


  • Wow, ist das aufwendig im Vergleich zu schon gezeigten Algos, die im Grunde die gleiche Idee umsetzen.



  • @rustyoldguy Das ist überflüssiges Verschieben.



  • @rustyoldguy sagte in Lottozahlen ohne Wiederholung:

    Hab mal ein Verschlüsselungsproggi geschrieben

    Hast du deine Variablennamen verschlüsselt? 😉

    slei, wohin, dmog, sleia, finito, setzeog, genzuza, zuzaar
    


  • Ächz... zu viele gotos. Das geht besser.



  • und die globale variable kann man auch durch eine statische ersetzen.



  • @rustyoldguy sagte in Lottozahlen ohne Wiederholung:

    Warum orientierst du dich nicht am "Original?"

    Weil das gezeigte "Original" ganz fürchterlicher Quellcode ist und mit C++ schonmal gar nichts zu tun hat? Vor 20 Jahren hat man das vielleicht so umgesetzt, aber in der heutigen Zeit ist das die Sorte Quellcode, die man nicht weiter verbreiten sollte.


  • Mod

    @It0101 sagte in Lottozahlen ohne Wiederholung:

    Weil das gezeigte "Original" ganz fürchterlicher Quellcode ist und mit C++ schonmal gar nichts zu tun hat? Vor 20 Jahren hat man das vielleicht so umgesetzt, aber in der heutigen Zeit ist das die Sorte Quellcode, die man nicht weiter verbreiten sollte.

    Vor 20 Jahren war Jahrtausendwende 😮
    Mach 60 Jahre draus, dann bist du ungefähr bei der Zeit wo solcher Code noch halbwegs akzeptabel war. "Go To Statement Considered Harmful" ist von 1968!



  • @SeppJ sagte in Lottozahlen ohne Wiederholung:

    @It0101 sagte in Lottozahlen ohne Wiederholung:

    Weil das gezeigte "Original" ganz fürchterlicher Quellcode ist und mit C++ schonmal gar nichts zu tun hat? Vor 20 Jahren hat man das vielleicht so umgesetzt, aber in der heutigen Zeit ist das die Sorte Quellcode, die man nicht weiter verbreiten sollte.

    Vor 20 Jahren war Jahrtausendwende 😮
    Mach 60 Jahre draus, dann bist du ungefähr bei der Zeit wo solcher Code noch halbwegs akzeptabel war. "Go To Statement Considered Harmful" ist von 1968!

    Ich habe mit C bzw. C++ erst um die Jahrtausendwende angefangen, daher kann ich nicht bewerten was vorher war. Das "GOTO" mies ist, habe ich aber schon im Informatikunterricht anfang der 90er gelernt, weil das auch in Pascal ne blöde Idee war 😉



  • Hab ich ja wirklich 1995 geschrieben.
    Kann man aber sehr sehr sehr leicht umschreiben.
    Der Hacken ist eben, bei nur 6 aus 49 Zahlen kann man fast jedes System nutzen, um das
    ohne Wiederholung hinzukriegen. Wenn man aber per Transposition chiffrieren will und
    Zahlenreihen bis 13072 permutieren will, bleibt dir nur eine Kürzung eines bereits mit Zahlen
    befüllten Arrays übrig bei einer Permutierung einer Zahlenreihe wie die zuletzt genannte,
    kann das schon einige Minuten dauern. Mal abgesehen davon das die Zufallszahlengenerierung
    Systemabhängig ist. Bei Windows-Systemen liegt diese bei 0 bis 32767. Bei Linux-Systemen ist
    die Grenze bei etwa 200 000. Blöderweise kann man dabei keinen "Fortschrittsbalken" programmieren,
    da so lange die Z-Zahlen generiert werden, nichts am Terminal dargestellt werden kann.

    Aber die Sache mit dem Array und dem Kürzen wird zum Beispiel wichtig, wenn du Kartenspiele
    programmierst. Eine Karte die man ausgegeben hat, ist eben nicht mehr im Talon. Wenn du
    zum Beispiel Tarot nimmst, etwa Raider Wait Lenormand oder wie sie alle heißen, wie willst du sicher
    gehen, das eine Karte nicht mehr als einmal ausgegeben wird?

    Angeblich sollen ja auch gewisse amerikanische Geheimdienste die Finger drinn gehabt haben, als man
    festgelegt hat, auf welche Weise eine Zufallszahl generiert wird. Denn ab einer bestimmten Menge wird sich
    eine Wiederholung einstellen. Ist diese Spanne bisa zur Wiederholung zu groß, wetzen sich die Schlapphüte daran mal die Zähne ab.

    Übrigens gab es in Pascal das GOTO nicht. Der Programmrer sollte zu Objektorientierten Denken angeregt werden.
    Das Goto zu umgehen, sollte für jeden ein Kinderspiel sein.

    Ich war blos zu faul, das ganze vorher zu tun. Das überlasse ich den andern. Warum die Lösung gleich auf
    dem Silbertablett präsentieren?



  • @rustyoldguy
    Dein Code ist Schrott, einfach nur Schrott. Auch aus didaktischer Sicht.



  • Hab mal rum gekramt und eine "modernere Version gefunden":
    Zuerst genrand.h

    #ifndef GENRAND_H_INCLUDED
    #define GENRAND_H_INCLUDED
    
    #include  <iostream>
    #include  <time.h>
    
    
    void zeigezahlen(int zuzaar[], int zuzalimit);
    void initarreale(int obergrenze, int (*zuzaar)[66000], int (*schluessel)[66000], int (*wuerfel)[66000]);
    void kuerzearreal(int zuza, int og, int wuerfel[], int (*schluessel)[66000], int stelle);
    int getrand (int lowerlimit, int toprange);
    void testeareal(int og, int schluessel[]);
    
    #endif // GENRAND_H_INCLUDED
    

    Nun die dazugehörige genrand.cxx:

    #include "genrand.h"
    
    void zeigezahlen(int zuzaar[], int zuzalimit)
    {
    int zeize = 0, slei;
    std::cout << "\nZufallszahlen von 1 bis "<< zuzalimit << std::endl;
    
     for (slei = 0; slei < zuzalimit; slei++)
      {
      std::cout << "Nr." << slei << " = " << zuzaar[slei];
      zeize++;
      if (zeize >= 6) { std::cout << std::endl;; zeize = 0; }
      }
    }
    
    void initarreale(int obergrenze, int (*zuzaar)[66000], int (*schluessel)[66000], int (*wuerfel)[66000])
    {
    int slei;
     if (obergrenze > 65536) obergrenze = 65536;
    
     for (slei = 0; slei < 66000; slei++)
      {
       (*wuerfel)[slei] = 0;
       (*zuzaar)[slei] = 0;	
       (*schluessel)[slei] = 0; 	  
      }
    	  
     for (slei = 0; slei < obergrenze; slei++)
      (*wuerfel)[slei] = slei;
     
    }
    
    void kuerzearreal(int zuza, int og, int wuerfel[], int (*schluessel)[66000], int stelle)
    {
    int slei;
    
    (*schluessel)[stelle] = wuerfel[zuza];
    for (slei = zuza; slei < og; slei++)
     {
        wuerfel[slei] = wuerfel [slei + 1];
     }
     //std::cout << "\nog: " << og << "zuza: " << zuza << " stelle:" << stelle << "nach Kuerzung:   ";
     //for (slei = 0; slei < (og - 1); slei++)
     //std::cout << " -" << wuerfel[slei] << "- ";
    }
    int initrandom = 0;
    
    //generiert Zufallszahlen von 1 bis 65536
    int getrand(int min, int max)
    {
    int zuza, zuza2, zuza3, rewer;
    
     if (initrandom == 0)
      {
      srand (time (NULL));
      initrandom = 1;
      }
    
    zuza  = rand();
    zuza2 = (max - min); // + 1);
    zuza3 = zuza % zuza2;
    rewer = zuza3 + min;
    return rewer;
    }
    
    
    /* Errechnet die Summe aller Elemente des Zufallszahlenarreals */
    void testeareal(int og, int schluessel[])
    {
     int slei, dummy = 0, erge = 0;
    
    for (slei = 0; slei < og; slei++)
     {
      dummy += slei;
      erge += schluessel[slei];
     }
    std::cout << "\nAnzahl: "<< og << " Schlüssel: " << erge << "  Testwert: " << dummy << std::endl;
    if (erge != dummy)
     std::cout << "Fehler bei der Erstellung der Zufallszahlen" << std::endl;		
    }
    
    

    Jetzt main.cc:

    /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*-  */
    /*
     * main.cc
     * Copyright (C) 2017 rustyoldguy
     * 
     * genzufallszahlen is free software: you can redistribute it and/or modify it
     * under the terms of the GNU General Public License as published by the
     * Free Software Foundation, either version 3 of the License, or
     * (at your option) any later version.
     * 
     * genzufallszahlen is distributed in the hope that it will be useful, but
     * WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     * See the GNU General Public License for more details.
     * 
     * You should have received a copy of the GNU General Public License along
     * with this program.  If not, see <http://www.gnu.org/licenses/>.
     *
     * Demonstrates how to generate a random| number between 1 and a given value.
     *
     * NOTE: In real use, you would not want| to call srand() before every call to
     * rand(), because if you call rand()| quickly in succession, it will keep
     * returning the same results. Instead,| move the call to srand to the beginning
     * of your program and only call it once. It works in this program, but only
     * because getrand() is called a single| time.
     */
    #include "genrand.h"
    
    
    int main (void)
    {
     int untergrenze, toprange = 49, slei, wohin = 8, dmog, sleia, zuza, anzahl = 6;
     int zuzaar[66000], schluessel[66000], wuerfel[66000];
     //int percent, vzaehler, vist;	
    
    untergrenze = 0;
    
    do
    switch(wohin)
    {
    default:
        std::cout << std::endl << "Zufallszahlengenerator" << std::endl;
        std::cout << "Obergrenze: " << toprange << std::endl;
        std::cout << "Ende...........................1" << std::endl;
        std::cout << "Obergrenze eingeben............2" << std::endl;
        std::cout << "Zahlen generieren..............3" << std::endl;
        std::cout << "Nur Zufallszahlen generieren...4" << std::endl;
        std::cout << "Anzahl der Zufallszahlen.......5" << std::endl;
        std::cout << "Ihre Wahl: ";
        std::cin >> wohin;
       break;
    
       case 1:
         std::cout <<  "Programmende" << std::endl;
         return 0;
        break;
    
    
    
       case 2:
         std::cout <<  "Obergrenze: (max 32768)";
         std::cin >> toprange;
         wohin = 8;
        break;
    
       case 3:
           std::cout << "Generiere Zahlen" << std::endl;
           if (toprange > 65536) toprange = 65536;
          initarreale(toprange, &zuzaar, &schluessel, &wuerfel);
    
          //zeigezahlen(zuzaar, toprange);
          //zeigezahlen(schluessel, toprange);
          //zeigezahlen(wuerfel, (toprange + 3));
          dmog = toprange;
          sleia = 0;
          // percent = toprange / 100;
    	  // vzaehler = vist = 0;	
    		
          for (slei = 0; slei < toprange; slei++)
           {
            zuzaar[slei] = getrand(untergrenze, dmog);
            kuerzearreal(zuzaar[slei], toprange, wuerfel, &schluessel, sleia);
            sleia++;
            dmog--;
            /*if (vzaehler++ > percent)
    		  {
               vist++;  
               std::cout << vist << "% ";
    		   vzaehler = 0;	
    		  }	
    		   */
    		if (dmog == 0 ) break;
           }
            
    	// Generierte Zufallszahlen zeigen
        // zeigezahlen(zuzaar, toprange);
        // zeigezahlen(schluessel, toprange);
        testeareal(toprange, schluessel);
    	std::cout << "Zahlen wurden generiert." << std::endl;
    		
    		
      wohin = 8;
     break;
    
     case 4:
         std::cout << "Nur " << anzahl << " Zufallszahlen generieren" << std::endl;
         for (slei = 0; slei < anzahl; slei++)
          {
          zuza = getrand (0, toprange);
           std::cout << " -" << zuza << "- " << std::endl;
          }
         std::cout << std::endl;
         wohin = 8;
        break;
    
    case 5:
        std::cout << "Bitte Anzahl der zu generierenden Zufallszahlen eingeben (maximal " << anzahl << ")" << std::endl;
        std::cin >> anzahl;
     break;
    
    }
    while(wohin != 0);
    
     return 0;
    }
    
    
    Was die Sache mit RAND_MAX angeht:
    ```cpp
    #include <iostream>
    #include <cstdlib>
    
    int main(void)
    {
     std::cout << "Wert von RAND_MAX: " << RAND_MAX << std::endl;
    	
     return 0;
    }
    


  • #Ausgabe bei mir:
    Wert von RAND_MAX: 2147483647



  • @Wutz sagte in Lottozahlen ohne Wiederholung:

    @rustyoldguy
    Dein Code ist Schrott, einfach nur Schrott. Auch aus didaktischer Sicht.

    /*
    "Anyone who consider arithmetic means of producing random number is,
    of course, in a state of sin" - John Von Neumann
    */

    In Wikipedia:
    https://de.wikipedia.org/wiki/John_von_Neumann

    Wer nicht weis was er mit seiner Freizeit unsinniges anfangen soll:
    https://www.subroutine.info/elektronik/zufallsgenerator/

    http://www.jtxp.org/tech/xr232web.htm

    http://www.hcrs.at/NOISE.HTM

    Heir was für( masochistisch veranlagte) Programmierer und Mathe-Freaks:
    https://123mathe.de/zufallsvariable-wahrscheinlichkeitsverteilungen-erwartungswert

    Meine Erfahrungen in der Stochastik:
    Ich habe mich immer gefragt was wohl trockener ist, die Wüste Gobi oder
    Kurvendiskussion, Stochastik, Wahrscheinlichkeitsverteilungen.
    Ich denke die Wüste Gobi ist weniger trocken!

    Zum Schluss:
    https://www.welt.de/wissenschaft/article1924410/Wie-kommt-der-Zufall-in-den-PC.html



  • @rustyoldguy sagte in Lottozahlen ohne Wiederholung:

    Übrigens gab es in Pascal das GOTO nicht

    Gab es übrigens doch.



  • @rustyoldguy sagte in Lottozahlen ohne Wiederholung:

    Hab mal rum gekramt und eine "modernere Version gefunden":

    da ist ja auch wieder eine globale variable drin.😃



  • @Wade1234 sagte in Lottozahlen ohne Wiederholung:

    da ist ja auch wieder eine globale variable drin.

    Das wär mir jetzt z.B. gar nicht erst aufgefallen, weil ich das auf den ersten Blick allein schon optisch so dermaßen hässlich finde, dass ich auf solche Details gar nicht mehr achte.
    @rustyoldguy nichts für ungut, nimmts nicht persönlich. Solchen Code will man zumindest in diesem Jahrtausend einfach nicht sehen.