Forum: Mikrocontroller und Digitale Elektronik Frage zur Modulo % Berechnung


von M. G. (ixil96)


Lesenswert?

Hallo,

ich möchte ein "Würfelspiel" programmieren (im Atmel Studio Simulator) 
und mit dem folgenden Beispiel sehen, wie oft eine "zufällige Zahl" bei 
10000 Versuchen gewürfelt wurde.
Aber ich erhalte als Wert für zz immer 5"

Was mache ich falsch?
1
#include <stdlib.h>
2
#include <avr/io.h>
3
4
uint16_t zufallszahl, zz, wuerfelzahl, eins=0, zwei=0, drei=0, vier=0, fuenf=0, sechs=0;
5
6
int main(void)
7
{
8
  for (uint16_t i=0; i<10000; i++)
9
  {
10
    zufallszahl = rand();
11
    zz = zufallszahl % 6;
12
    wuerfelzahl = zz + 1;
13
    
14
    if (wuerfelzahl == 1)
15
      eins ++;
16
    else if (wuerfelzahl == 2)
17
      zwei ++;
18
    else if (wuerfelzahl == 3)
19
      drei ++;
20
    else if (wuerfelzahl == 4)
21
      vier ++;
22
    else if (wuerfelzahl == 5)
23
      fuenf ++;
24
    else if (wuerfelzahl == 6)
25
      sechs ++;
26
  }
27
}

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

m. g. schrieb:
> Was mache ich falsch?

Du vertraust zu sehr dem Simulator.

von Daniel A. (daniel-a)


Lesenswert?

https://xkcd.com/221/

Am sichtbaren code liegt's nicht.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

m. g. schrieb:
> Was mache ich falsch?
Du initialisierst den Zufallsgenerator nicht mit einer Zufallszahl. Und 
rand() berechnet immer nur eine Zufallszahl aus der vorherigen 
Zufallszahl. Wenn du also immer mit 0 startest, kommt als nächste Zahl 
immmer 5...

Das Stichwort ist: seed()

Daniel A. schrieb:
> Am sichtbaren code liegt's nicht.
So ist es:
http://codepad.org/PZAlZSmo

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lothar M. schrieb:
> m. g. schrieb:
>> Was mache ich falsch?
> Du initialisierst den Zufallsgenerator nicht mit einer Zufallszahl. Und
> rand() berechnet immer nur eine Zufallszahl aus der /vorherigen/
> Zufallszahl. Wenn du also immer mit 0 startest, kommt als nächste Zahl
> immmer 5...

Wo steht denn im Source, dass er immer mit 0 startet? Dann müsste er 
auch vor jedem rand() erst seed() mit 0 aufrufen. Tut er aber nicht. 
rand() berechnet die nächste Zufallszahl aus rand(). Wenn die immer 
gleich wäre, kannst Du rand() in die Tonne kloppen. Daher tippe ich 
weiter auf den Simulator, der schon in vielen AVR-Threads der böse Bube 
war.

Habe den obigen Source leicht geändert für Linux:
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stdint.h>
4
5
uint16_t zufallszahl, zz, wuerfelzahl, eins=0, zwei=0, drei=0, vier=0, fuenf=0, sechs=0;
6
7
int main(void)
8
{
9
  uint16_t i;
10
11
  for (i=0; i<10000; i++)
12
  {
13
    zufallszahl = rand();
14
    zz = zufallszahl % 6;
15
    wuerfelzahl = zz + 1;
16
17
    if (wuerfelzahl == 1)
18
      eins ++;
19
    else if (wuerfelzahl == 2)
20
      zwei ++;
21
    else if (wuerfelzahl == 3)
22
      drei ++;
23
    else if (wuerfelzahl == 4)
24
      vier ++;
25
    else if (wuerfelzahl == 5)
26
      fuenf ++;
27
    else if (wuerfelzahl == 6)
28
      sechs ++;
29
  }
30
  printf ("%d %d %d %d %d %d\n", eins, zwei, drei, vier, fuenf, sechs);
31
  return 0;
32
}

Ergebnis:
1
$ cc rand.c -o rand && ./rand
2
1655 1694 1761 1595 1671 1624

Also schön verteilt.

von Piet (Gast)


Lesenswert?

Das sagt Google dazu:
In der Bibliothek stdlib.h gibt es die Funktion rand(), welche eine 
Pseudo-Zufallszahl zurückgibt. Die Zahl liegt zwischen 0 und einer 
maximalen Zahl, welche mit der symbolischen Konstante RAND_MAX abgefragt 
werden kann. Möchte man den Bereich der Zufallszahl eingrenzen, kann der 
Modulo-Operator verwendet werden. Bevor die Zufallszahlen erstellt 
werden, sollte die Funktion srand() aufgerufen werden. Diese 
initialisiert den Zufallszahlen-Generator, um die Zufälligkeit der 
Zahlen zu gewährleisten. Im Parameter wird ein Zeitstempel übergeben, 
deshalb muss auch die time.h eingebunden werden.

http://www.c-howto.de/tutorial-uebungen-teil1.html

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Piet schrieb:
> Bevor die Zufallszahlen erstellt werden, sollte die Funktion srand()
> aufgerufen werden.
Aber nur deshalb, weil sonst bei jedem Programmstart die gleiche 
Zufallszahlensequenz kommt.

Mit srand() gibts hier z.B. immer unterschiedliche Verteilung:
http://codepad.org/bYnXBNA2
http://codepad.org/KEhj5dr4

Ohne srand() immer die gleiche:
http://codepad.org/3Tb2LzcD
http://codepad.org/1cm5k5lq

Frank M. schrieb:
> Daher tippe ich weiter auf den Simulator, der schon in vielen
> AVR-Threads der böse Bube war.
Man müsste wissen, was rand() genau macht. Denn diese Funktion 
funktioniert hier offenbar nicht...

von Karl H. (kbuchegg)


Lesenswert?

Frank M. schrieb:
> m. g. schrieb:
>> Was mache ich falsch?
>
> Du vertraust zu sehr dem Simulator.

Muss nicht sein. Kann auch eine Fehlbedienung bzw. Fehlinterpretation 
sein.
Gerade Neulinge sind mit dem Wort 'dauernd' oft sehr voreilig.
Er steppt einmal durch den Code und kriegt eine 5. Dann steppt er in der 
Schleife weiter und die nächste von rand() gelieferte Zahl mündet wieder 
in einer 5 und schon ist das 'dauernd'.
Oder er startet das Programm neu und kriegt (no na) wieder als erste 
Würfelzahl eine 5.

Das rand() nicht funktioniert können wir wahrscheinlich ausschliessen. 
rand() ist keine Raketentechnik sondern simpel - und das 
plattformübergreifend.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.