Forum: Mikrocontroller und Digitale Elektronik srand() und rand()


von Bastel (Gast)


Lesenswert?

Hallo zusammen,

ich würde gerne auf einem ATMEGA 8 eine Zufallszahl generieren und habe 
damit keine Erfahrung. Ich würde dazu gerne srand() und rand() benutzen. 
Hierzu habe ich aber ein, zwei Fragen:
Liefert mir dieser Code immer neue Zahlen zwischen 0 und 9?
1
#define RAND_MAX 9
2
uint8_t zufallszahl;
3
uint32_t seed = 1;
4
srand(seed);
5
6
while(1)
7
{
8
zufallszahl = rand();
9
}

Gibt es auch eine Möglichkeit RAND_MAX dynamisch zu gestalten? 
Eigentlich brauche ich immer eine Zahl von 0-9 UND eine Zahl von 0-6.

Kann ich für seed auch einen Wert aus dem EEPROM wählen, den ich bei 
jedem Start erhöhe, damit die Werte nicht bei jedem Neustart identisch 
sind?

von Rolf Magnus (Gast)


Lesenswert?

Bastel schrieb:
> Liefert mir dieser Code immer neue Zahlen zwischen 0 und 9?

Nein.

> #define RAND_MAX 9

RAND_MAX wird von der Implementation definiert und gibt an, in welchem 
Bereich rand() arbeitet. Du kannst jetzt an der Stelle zwar behaupten, 
dieser Wert wäre 9, aber rand() ist das ziemlich egal.

> Gibt es auch eine Möglichkeit RAND_MAX dynamisch zu gestalten?

Nein.

> Eigentlich brauche ich immer eine Zahl von 0-9 UND eine Zahl von 0-6.

Du kannst z.B. rand() % 9 machen. Dann ist deine Zahl im Bereich 0 bis 
9.

> Kann ich für seed auch einen Wert aus dem EEPROM wählen, den ich bei
> jedem Start erhöhe, damit die Werte nicht bei jedem Neustart identisch
> sind?

Ja. Genau um sowas zu machen ist srand() ja da.

von Ingo W. (Gast)


Lesenswert?

Rolf Magnus schrieb:

> Du kannst z.B. rand() % 9 machen. Dann ist deine Zahl im Bereich 0 bis
> 9.

Wird wohl in diesem Falle ausreichend funktionieren, verzerrt aber etwas 
die Gleichverteilung, da i.d.R RAND_MAX kein Vielfaches von 10 ist.
Ein unrealistisches Extrembeispiel zur Verdeutlichung wäre RAND_MAX==15, 
da würden die Werte 0..5 doppelt so häufig rauspurzeln, wie 6..9.

besser (und wohl auch nicht aufwändiger) wäre wohl
ergebnis=rand()/RAND_MAX*WunschMax;
was aber einen breiteren Ergebnistyp (oder Gleitkomma, im µC wohl nicht 
so gut) erfordern würde. Nur mal so, zum im Hinterkopf behalten.
Modulodivision ist da etwas Ressourcenschonender.
nix für ungut...

von Stefan R. (srand)


Lesenswert?

Und nur zur Ergänzung: Sofern der "Wunschzielbereich" den "tatsächlichen 
Zielbereich von rand()" fast ausfüllt, ist es meistens am einfachsten, 
einfach rand() solange aufzurufen, bis der Wert im gewünschten Bereich 
ist.

Das ist die einfachste Art, Verzerrungen der 
Wahrscheinlichkeitsverteilung zu vermeiden.

von Rolf Magnus (Gast)


Lesenswert?

Ingo Wendler schrieb:
> besser (und wohl auch nicht aufwändiger) wäre wohl
> ergebnis=rand()/RAND_MAX*WunschMax;
> was aber einen breiteren Ergebnistyp (oder Gleitkomma, im µC wohl nicht
> so gut) erfordern würde.

Den Ergebnistyp nicht unbedingt, aber das Zwischenergebnis für 
RAND_MAX*WunschMax muß halt größer als int sein, um den Wert aufnehmen 
zu können, auf dem AVR also 32 Bit.

> Modulodivision ist da etwas Ressourcenschonender.

Deshalb hatte ich die auch vorgeschlagen.

von ein gast (Gast)


Lesenswert?

Bastel schrieb:
> Kann ich für seed auch einen Wert aus dem EEPROM wählen, den ich bei
> jedem Start erhöhe, damit die Werte nicht bei jedem Neustart identisch
> sind?

Du kannst auch folgende Funktion verwenden
1
#include <avr/io.h>
2
 
3
unsigned short get_seed()
4
{
5
   unsigned short seed = 0;
6
   unsigned short *p = (unsigned short*) (RAMEND+1);
7
   extern unsigned short __heap_start;
8
    
9
   while (p >= &__heap_start + 1)
10
      seed ^= * (--p);
11
    
12
   return seed;
13
}
Quelle: 
http://www.rn-wissen.de/index.php/Zufallszahlen_mit_avr-gcc#Startwert_.28seed.29_besorgen

Der RAM ist nach einschalten in einem nicht-definierten Zustand (sofern 
nicht selber initialisiert) und somit bekommt man mit sehr hoher 
wahrscheinlichkeit nicht 2x hintereinander den gleichen seed.

von Ingo W. (Gast)


Lesenswert?

Ingo Wendler schrieb:
>
> besser (und wohl auch nicht aufwändiger) wäre wohl
> ergebnis=rand()/RAND_MAX*WunschMax;

Ziehe meinen Beitrag zurück, bei der Division wäre die Gleichverteilung 
auch nicht besser.

von (prx) A. K. (prx)


Lesenswert?

Bastel schrieb:
> Kann ich für seed auch einen Wert aus dem EEPROM wählen, den ich bei
> jedem Start erhöhe, damit die Werte nicht bei jedem Neustart identisch
> sind?

Im Prinzip schon, aber mit Zufall hat das Ergebnis dann nichts zu tun, 
sondern ist exakt reproduzierbar. Das kann egal sein, kann aber auch ein 
Problem sein, je nach Aufgabe.

von Bastel (Gast)


Lesenswert?

Danke für den ganzen Input. Das Problem ist damit mehr als gelöst :)
Ich mache es mit rand() % 9. Für meine Anwendung ist die 
Wahrscheinlichkeitsverteilung und Reproduzierbarkeit völlig unkritisch.

von Georg G. (df2au)


Lesenswert?

ein gast schrieb:
> Der RAM ist nach einschalten in einem nicht-definierten Zustand

Das darf man wohl bezweifeln. Das RAM in gängigen Prozessoren ist 0xff 
oder 0x00 nach dem Einschalten, ggfs einige Bänke so, andere so. Was 
anderes ist mir noch nie begegnet.

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.