Zufallszahlen



  • Hallo Leute,

    in meinem Programm will ich nichts weiter als 4 Zufallszahlen generieren.
    Bei num1 und num2 funktioniert das auch wie gewollt.
    mal1 und mal2 werden jedoch immer gleich generiert.
    Muss ich hierbei irgendetwas spezielles beachten?

    Hier der Ausschnitt meines Problems:

    int num1, num2;
    int mal1, mal2;
    
    srand((unsigned)time(NULL));
    
    
    num1 = rand() % 100 + 1;
    num2 = rand() % 100 + 1;
    
    mal1 = rand() % 10 + 1;
    mal2 = rand() % 10 + 1;


  • #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    
    int main(void)
    {
    	srand((unsigned)time(NULL));
    
    	int num1 = rand() % 100 + 1;
    	int num2 = rand() % 100 + 1;
    
    	int mal1 = rand() % 10 + 1;
    	int mal2 = rand() % 10 + 1;
    
    	printf("%d %d %d %d\n", num1, num2, mal1, mal2);
    }
    

    Output:

    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    76 38 8 9
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    79 86 2 2
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    82 34 8 8
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    85 15 4 3
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    89 63 8 6
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    92 12 4 2
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    95 92 9 7
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    95 92 9 7
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    98 41 5 2
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    2 89 9 6
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    5 69 5 1
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    5 69 5 1
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    8 18 9 6
    
    C:\Users\sword\source\repos\Codefun\x64\Debug>Codefun.exe
    11 66 5 2
    

    Was passt dir daran nicht? Wenn dein Code für mal1 und mal2 immer die selben Werte hat machst du irgendetwas anders das nicht aus deinem Schnipsel hervorgeht.

    btw. Du hast das C-Forum knapp verfehlt, das wäre hier gewesen. Ein Moderator wird das Thema irgendwann verschieben.



  • @siebererrene kann es sein, dass bei der Überprüfung der Werte zweimal mal1 bzw. mal2 steht?



  • @DirkB Hab bei der Übergabe an die Funktion 2 mal "mal1" gehabt... aiaiai

    Danke für die schnellen Antworten und sorry, dass ich das C-Forum gemisst habe.

    Lg
    Rene



  • Am besten mal lernen, wie man den Debugger bedient. Das spart eine Menge Zeit.



  • Hallo Swordfish!

    Zum besseren Verständnis sieh dir mal folgende code-Sequenz an:

    int initrandom = 0;
    
      //generiert Zufallszahlen von 1 bis 32767;
    int getrand(int min, int max)
    {
    int zuza, range, zuza3, rewer;
    // bis 32767
     //srand (time (NULL));
     if (initrandom == 0)
      {
      srand (time (NULL));
      initrandom = 1;
      }
    
    max++;
    zuza  = rand();
    printf("urzuza: %d\n", zuza);
    range = (max - min); // + 1);
    zuza3 = zuza % range;
    rewer = zuza3 + min;
    return rewer;
      srand (time (NULL));
    }
    

    Wenn man innerhalb der Laufzeit eines Programms jedes mal srand() startet erhält
    man immer die selben Werte. Um das zu verhindern dient die globale Variable
    "initrandom", welche vor dem Start auf NULL gesetzt wird. Ruft man dann die Funktion
    getrand() auf, wird automatisch geprüft, ob srand() schon gestartet wurde.
    Innerhalb von getrand() wird die Funktion rand() aufgerufen.
    Diese erzeugt eine Zufallszahl zwischen 0 und RAND_MAX.

    Diese Konstante ist in den headern<cstdlib> (stdlib.h)
    definiert.

    Bei UNIX-Systemen und deren Derivaten(Linux, BSD) kann RAND_MAX durchaus andere Werte
    annehmen als bei Windows-Systemen. Ganz zu schweigen vom Compiler.
    Man kann sich auch folgende Zeile reinbasteln um deren Größe zu erhalten:

      printf("RAND_MAX: %d\n", RAND_MAX);
    

    Auf meinem Linux-System(64Bit, SUSE-Linux Tumbleweed, Kernel 4.19.11-1
    mit GCC 8.2.1 und codeblocks 17.12 rev. 11256)
    ist die Größe der Konstante 2147483647

    Wie man aus dem Beispiel ersehen kann, beinhaltet die Variable "range"(englisch für Spannweite)
    die Spannweite zwischen der kleinsten gewünschten Zufallszahl(min) und der größten (max).
    Danach wird der Divisionsrest von der mit rand() erzeugten Zufallszahl und der
    Spannweite errechnet. Logisch das dieser Divisionsrest niemals größer sein kann
    als die Spannweite (=max - min). Theoretisch kann dieser Divisionsrest auch Null sein.
    Deshalb wird anschließend der gewünschte Minimalwert dazu addiert.
    In deinem Fall ist bei mal1 und mal2 die Spannweite 10 und der gewünschte Minimalwert 1.
    Bei der Funktion getrand() müsstest du also als ersten Parameter 1 und beim zweiten 11 angeben.
    Man könnte auch ein Array allokieren und dieses mit Zufallszahlen füllen und später
    eine Häufigkeitsanalyse vornehmen.

    Dazu sollte man sich folgend Aussage vor Augen halten:

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

    Siehe zur Person:
    https://de.wikipedia.org/wiki/John_von_Neumann

    Wer sich dafür interessiert, wie so ein Source-Code für diese Funktionen aussieht, für den habe ich
    aus einer uralten CD mal folgendes Beispiel ausgegraben:

    /************************************************************************
     This random number generator originally appeared in "Toward a Universal
     Random Number Generator" by George Marsaglia and Arif Zaman.
     Florida State University Report: FSU-SCRI-87-50 (1987)
    
     It was later modified by F. James and published in "A Review of Pseudo-
     random Number Generators"
    
     Converted from FORTRAN to C by Phil Linttell, James F. Hickling
     Management Consultants Ltd, Aug. 14, 1989.
    
     THIS IS THE BEST KNOWN RANDOM NUMBER GENERATOR AVAILABLE.
           (However, a newly discovered technique can yield
             a period of 10^600. But that is still in the development stage.)
    
     It passes ALL of the tests for random number generators and has a period
       of 2^144, is completely portable (gives bit identical results on all
       machines with at least 24-bit mantissas in the floating point
       representation).
    
     The algorithm is a combination of a Fibonacci sequence (with lags of 97
       and 33, and operation "subtraction plus one, modulo one") and an
       "arithmetic sequence" (using subtraction).
    
     On a Vax 11/780, this random number generator can produce a number in
        13 microseconds.
    ************************************************************************/
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <time.h>
    
    #define TRUE    1
    #define FALSE   0
    
    float u[97], c, cd, cm;
    int i97, j97, test;
    
    int rmarin(int ij, int kl);
    int ranmar(float rvec[], int len);
    void sow( int *seed1, int *seed2 );
    
    
    int main()
    {
    
            float temp[100];
            int i;
            int ij, kl, len;
    
            /*These are the seeds needed to produce the test case results*/
            sow( &ij, &kl);
            //ij = 1802;
            //kl = 9373;
    
            /*Do the initialization*/
    
            if (1 == rmarin(ij,kl))
                    return 1;
    
            /*Generate 20000 random numbers*/
    
            len = 100;
            for ( i=0; i<=199 ; i++)
                    if (1 == ranmar(temp, len))
                            return 1;
    
            /*If the random number generator is working properly,
              the next six random numbers should be:
    
                6533892.0  14220222.0   7275067.0
                6172232.0   8354498.0  10633180.0
            */
    
            len = 6;
            if (1 == ranmar(temp, len))
                    return 1;
    
            for ( i=0; i<=5; i++)
                    printf("%12.1f\n",4096.0*4096.0*temp[i]);
    
      return 0;
    }
    
    
    /************************************************************************
     This is the initialization routine for the random number generator RANMAR()
     NOTE: The seed variables can have values between:    0 <= IJ <= 31328
                                                          0 <= KL <= 30081
     The random number sequences created by these two seeds are of sufficient
     length to complete an entire calculation with. For example, if several
     different groups are working on different parts of the same calculation,
     each group could be assigned its own IJ seed. This would leave each group
     with 30000 choices for the second seed. That is to say, this random
     number generator can create 900 million different subsequences -- with
     each subsequence having a length of approximately 10^30.
    
     Use IJ = 1802 & KL = 9373 to test the random number generator. The
     subroutine RANMAR should be used to generate 20000 random numbers.
     Then display the next six random numbers generated multiplied by 4096*4096
     If the random number generator is working properly, the random numbers
     should be:
               6533892.0  14220222.0   7275067.0
               6172232.0   8354498.0  10633180.0
    ************************************************************************/
    
    int rmarin(int ij, int kl)
    {
    
            float s, t;
            int i, j, k, l, m;
            int ii, jj;
    
            /* Change FALSE to TRUE in the next statement to test the
               random routine.*/
    
            test = TRUE;
    
            if ( ( ij < 0 || ij > 31328 ) ||
                    ( kl < 0 || kl > 30081 ) )
            {
                    printf ("RMARIN: The first random number seed must have a "
                            "value between 0 and 31328\n");
                    printf ("        The second random number seed must have a "
                            "value between 0 and 30081");
                    return 1;
            }
    
            i = fmod(ij/177.0, 177.0) + 2;
            j = fmod(ij      , 177.0) + 2;
            k = fmod(kl/169.0, 178.0) + 1;
            l = fmod(kl      , 169.0);
    
            for ( ii=0; ii<=96; ii++ )
            {
                    s = 0.0;
                    t = 0.5;
                    for ( jj=0; jj<=23; jj++ )
                    {
                            m = fmod( fmod(i*j,179.0)*k , 179.0 );
                            i = j;
                            j = k;
                            k = m;
                            l = fmod( 53.0*l+1.0 , 169.0 );
                            if ( fmod(l*m,64.0) >= 32)
                                    s = s + t;
                            t = 0.5 * t;
                    }
                    u[ii] = s;
            }
    
            c  =   362436.0 / 16777216.0;
            cd =  7654321.0 / 16777216.0;
            cm = 16777213.0 / 16777216.0;
    
            i97 = 96;
            j97 = 32;
    
            test = TRUE;
    
            return 0;
    }
    
    int ranmar(float rvec[], int len)
    {
            float uni;
            int ivec;
    
            if ( !test )
            {
                    printf ("RANMAR: Call the initialization routine (RMARIN) "
                            "before calling RANMAR.\n");
                    return 1;
            }
    
            for ( ivec=0; ivec < len; ivec++)
            {
                    uni = u[i97] - u[j97];
                    if ( uni < 0.0 )
                            uni = uni + 1.0;
                    u[i97] = uni;
                    i97--;
                    if ( i97 < 0 )
                            i97 = 96;
                    j97--;
                    if ( j97 < 0 )
                            j97 = 96;
                    c = c - cd;
                    if ( c < 0.0 )
                            c = c + cm;
                    uni = uni - c;
                    if ( uni < 0.0 )
                            uni = uni + 1.0;
                    rvec[ivec] = uni;
            }
            return 0;
    }
    
    /* I use the following procedure in TC to generate seeds:
    
      The sow() procedure calculates two seeds for use with the random number
      generator from the system clock.  I decided how to do this myself, and
      I am sure that there must be better ways to select seeds; hopefully,
      however, this is good enough.  The first seed is calculated from the values
      for second, minute, hour, and year-day; weighted with the second most
      significant and year-day least significant.  The second seed weights the
      values in reverse.
    */
    
    void sow( int *seed1, int *seed2 )
    {
            struct tm *tm_now;
            float s_sig, s_insig, maxs_sig, maxs_insig;
            long secs_now;
            int s, m, h, d, s1, s2;
    
            time(&secs_now);
            tm_now = localtime(&secs_now);
    
            s = tm_now->tm_sec + 1;
            m = tm_now->tm_min + 1;
            h = tm_now->tm_hour + 1;
            d = tm_now->tm_yday + 1;
    
            maxs_sig   = 60.0 + 60.0/60.0 + 24.0/60.0/60.0 + 366.0/24.0/60.0/60.0;
            maxs_insig = 60.0 + 60.0*60.0 + 24.0*60.0*60.0 + 366.0*24.0*60.0*60.0;
    
            s_sig      = s + m/60.0 + h/60.0/60.0 + d/24.0/60.0/60.0;
            s_insig    = s + m*60.0 + h*60.0*60.0 + d*24.0*60.0*60.0;
    
            s1 = s_sig   / maxs_sig   * 31328.0;
            s2 = s_insig / maxs_insig * 30081.0;
    
            *seed1 = s1;
            *seed2 = s2;
    }
    
    

    Betrachtet man das etwas angestaubte Beispiel genauer, dann sieht man, das man auch die
    Initialisierung per Eingabe einer Schlüsselzahl starten könnte.
    Dadurch würde man immer die selben Zahlen erhalten, egal wann man das Programm startet.
    Eigentlich nicht wünschenswert, es sei denn man will sich sein eigenes Verschlüsselungsprogramm
    basteln.
    Wichtig dazu folgende Webseiten:
    https://www.reddit.com/r/linux/comments/1lucdy/did_linus_torvalds_backdoor_linux_random_number/
    https://www.theregister.co.uk/2013/09/10/torvalds_on_rrrand_nsa_gchq/
    https://codepen.io/mottiden/pen/VbmZZN
    https://www.phoronix.com/scan.php?page=news_item&px=Linus-Torvalds-New-Politeness
    https://www.zdnet.com/article/a-kinder-gentler-linus-torvalds-and-linux-4-20/



  • @rustyoldguy sagte in Zufallszahlen:

    Wenn man innerhalb der Laufzeit eines Programms jedes mal srand() startet erhält man

    Wer hat irgendwo behauptet daß man srand() x-mal aufrufen soll? Rest: tl;dr.



  • Keiner!

    Aber es soll ja mehrere Leute geben, die c lernen wollen. Bevor sich diese
    die Finger wund Tippen, eine kleine Erklärung.



  • @rustyoldguy sagte in Zufallszahlen:

    eine kleine Erklärung.

    tjo. fail.



  • ähm du weißt schon, dass globale variablen beim programmstart mit 0 initialisiert werden, und du dir das daher sparen kannst?

    edit: wenn du mit unix tolle zufallszahlen haben willst, dann lies doch einfach aus /dev/urandom ein.😀



  • Normalerweise ja, sollte aber nur ein kleines Beispiel(von 1989 !!!) sein. Ich denke mal, das die meisten hier
    auf dem Forum dieses Beispiel für eigene Applikationen umschreiben können. Deshalb erübrigt sich so etwas.
    Die Ergebnisse der Zufallszahlen hängen immer davon ab, wie dessen Erzeugung initialisert wird.
    Die meisten werden das per Timer machen. Aber die Anzahl der erzeugten Zufallszahlen, ab der
    sich der Zahlen wiederholen, dürfte sich im Rahmen halten.
    So weit ich weis, hat da der amerikanische Geheimdienst was dagegen.

    https://www.elektroniknet.de/elektronik/halbleiter/nsa-algorithmus-findet-sich-in-blackberry-smartphones-und-tablets-104776.html

    Kleiner Exkurs:
    Als zum Beispiel Phil Zimmermann sein PGP schrieb, war damals der Aufwand zur Entschlüsselung
    laut Ansicht der Behörden zu hoch. Das führte dazu, das in mehreren Staaten, nicht nur in den USA
    Chiffrierungs-Software unter das Waffenrecht gestellt wurde. Wer sich in einigen Ländern solcher
    Software bedient, macht sich strafbar als Waffenhändler. Vor einigen Jahrzehnten gab es eine Organisation
    welche sich die Aufgabe Verschlüsselungssoftware für den Hausgebrauch nicht all zu gut werden zu lassen.
    Diese nannte sich so weit ich weis key recovery association

    Eine Möglichkeit zu Erzeugung etwa bei
    der Permutation von Texten auf Bit-Ebene ist ein Zahlenarray von bzw 0 bis 131072 per Erzeugung von
    Zufallszahlen durcheinander zu wirbeln. Also zu permutieren. rein theoretisch wären die Möglichkeiten
    dann 131072 Faktorielle, also 131072. Ich selbst habe damals Talarius geschrieben und dieses in
    QT geschriebenes Programm in einem anderen Forum ins Netz gestellt, nur als Lehrmittel!
    Lässt man eine bereits permutierte Zahlenreihe erneut permutieren, so lässt sich die Spanne, ab der sich
    die Zufallszahlen wiederholen, vergrößern.
    Dies ist enorm wichtig. Eigentlich dürfte ich dies hier nicht schreiben, aber auf Kurzwelle werden
    manche schon einmal auf Sender gestoßen sein, bei der Zahlenkolonnen gesendet werden.
    Etwa als Textform. Der Sprecher/in listet dann Zahlen auf wie
    "Neugen Acht", "Zero", Neugen vier drei " usw.
    Diese sind tatsächlich für Agenten bestimmt um so Nachrichten du dechiffrieren.
    Da die Frequenzen ohnehin oft gewechselt werden und eh nur kein Schwei* sich mehr für
    Kurzwelle interessiert, sollte dieser Kommentar kein Problem sein, oder?
    Analysiert man diese Zahlenreihen, so wird man auf sehr wenige Wiederholungen oder gar keine stoßen.
    Denn solche Wiederholungen erleichtern die Arbeit der Dechiffrierung in feindlichen Abteilungen sehr.
    Erzeugen kann man solche "echten" Zufallszahlen über das Verhalten bestimmter Halbleiter,
    Zehnerspannung oder das Raschverhalten bei Transistoren werden hierfür benutzt.
    siehe auch
    https://de.wikipedia.org/wiki/Rauschgenerator

    oder

    https://www.subroutine.info/elektronik/zufallsgenerator/
    http://www.ibbergmann.org/GRUNDLAGEN/
    http://www.jtxp.org/tech/xr232web.htm

    Mehr zu Zimmermann:
    https://de.wikipedia.org/wiki/Phil_Zimmermann

    Wer weniger Lust zum Löten hat:
    https://www.laser2000.de/de/signal-generatoren/1848-quanten-zufallszahlengenerator.html



  • Sorry sollte Rauschverhalten bei Transistoren(Unschärferelation beachten!) heißen.


  • Gesperrt

    @rustyoldguy sagte in Zufallszahlen:

    Wer weniger Lust zum Löten hat:

    Der besorgt sich einen Internet-Zugang: https://www.random.org/ 😀


Anmelden zum Antworten