hallo leute,
wie erzeuge ich eine zufallszahl mit random, die sich beim aufruf der
random funktion auch ändert? folgender quellcode liefert immer die
gleiche zahl:
void zufallszahl ()
{
int i;
rand ((unsigned) time(NULL));
for(i = 1; i <= 1; i++)
{
zahl = 0 + ( rand() % 255);
printf("erzeugte Zufallszahl %i \n\r" , zahl);
return (zahl);
}
}
ich benötige bei jedem aufruf von zufallszahl() allerdings eine andere
zahl zwischen 0 und 255.kann mir jemand weiterhelfen?!danke schonmal
Danke erstmal für die schnellen Antworten
@Emperor_L0ser (Gast)
ja hast recht, hab ich bei mir im Quellcode auch gemacht nur irgendwie
beim hierher kopieren gings verloren...;)
@CHRiS (Gast)
ich will halt nur einen Wert und keine Zahlenfolge....muss eigentlich
von 1 bis 2 heißen. Das war allerdings nicht der Fehler.
Das Problem ist, dass bei jedem Aufruf der Funktion der gleiche
zufallswert erzeugt wird und ich benötige unterschiedliche Werte...weiß
nicht wo der fehler liegen soll.
Hat noch jemand ne idee?
> rand ((unsigned) time(NULL));
Eigentlich sollte das einen Fehler vom Compiler bringen, es sei denn, du
hast den zur Funktion gehörenden Header nicht eingebunden. Dann sollte
aber wenigstens eine Warnung kommen. Du meintest vermutlich srand.
geht das?
1
for(i=1;i<=1;i++)
Gehen tut das schon. Die Schleife wird halt genau einmal ausgeführt.
srand() soll natürlich nur einmal ausgeführt werden und nicht bei jedem
Aufruf der Funktion erneut. Damit gibst du den Startwert vor, mit dem
der Generator initialisiert wird. Wenn du vor jedem Aufruf den Startwert
neu setzt, klappt das natürlich nur mäßig gut.
>Das Problem ist, dass bei jedem Aufruf der Funktion der gleiche> zufallswert erzeugt wird und ich benötige unterschiedliche Werte
Vermutlich nicht bei jedem Aufruf, sondern immer genau eine Sekunde lang
bzw bis time() einen neuen Wert liefert.
Um Zahlen von 0 bis 255 (0 und 255 eingeschlossen, was wahrscheinlich
deine Absicht ist) zu erzeugen, musst du %256, nicht %255 rechnen.
Der Typ von zufallszahl() sollte int sein.
> for(i = 1; i <= 2; i++)> ...> return (zahl);> ...
Warum zwei Schleifendurchläufe, wenn aus dem ersten sowieso per return
herausgesprungen wird? Wieso lässt du die Schleife nicht einfach ganz
weg?
Vereinfachte Variante:
> Um Zahlen von 0 bis 255 (0 und 255 eingeschlossen, was wahrscheinlich> deine Absicht ist) zu erzeugen, musst du %256, nicht %255 rechnen.
Meistens wird eher noch empfohlen, % gar nicht zu verwenden, sondern den
Wert passend runterzudividieren bzw -shiften, da manche
Zufallszahlengeneratoren bei den unteren Bits nicht so gut mit der
Zufallsverteilung sind wie bei den oberen bits. In der Manpage zu rand
unter Linux heißt es:
************
The versions of rand() and srand() in the Linux C Library use the same
random number generator as random() and srandom(), so the lower-order
bits should be as random as the higher-order bits. However, on older
rand() implementations, and on current implementations on different
systems, the lower-order bits are much less random than the higher-order
bits.
************
Es gibt noch ein 2-tes Problem mit der Modulo Version:
Die Normalverteilung von rand() kann empfindlich gestört werden.
Beispiel:
Angenommen der Zufallszahlengenerator liefert Zahlen im Bereich
0 bis 7. Um in den Bereich 0 bis 5 zu kommen wird gemacht:
rand() % 6
Um zu sehen, was hier passiert untersuchen wir mal, was bei jeder
einzelnen rand() Zahl durch den % 6 entsteht
Zahl von rand() % 6
0 0
1 1
2 2
3 3
4 4
5 5
6 0
7 1
Wenn also alle Zahlen die rand() liefert tatsächlich gleich
wahrscheinlich sind, dann macht die % 6 Rechnung daraus eine
Verteilung in der 0 und 1 doppelt so häufig auftreten wie 2,
3, 4, 5. Sowas wird jeden Kasinobetreiber in den Ruin treiben :-)
In C gibt es eine Konstante, aus der man die größte Zahl ablesen
kann, die von rand() geliefert werden kann: RAND_MAX
Nur dann wenn bei der Berechnung % n das n auch RAND_MAX teilt,
bleibt die Normalverteilung erhalten. In allen anderen Fällen
wird man sich mit dieser Methode einen Fehler in der Verteilung
einhandeln.
> Die Normalverteilung von rand() kann empfindlich gestört werden.
Das ist schon richtig, besonders auf 8- und 16-Bit-Systemen, wo der
Wertebereich der rand-Funktion nur bis 2**15-1=32767 reicht (bspw. auf
dem AVR). Du meinst aber sicher die Gleichverteilung, nicht die
Normalverteilung ;-).
> Nur dann wenn bei der Berechnung % n das n auch RAND_MAX teilt,
Nicht ganz korrekt: Das Gleichverteilung bleibt dann erhalten, wenn n
RAND_MAX+1 teilt. Die Zufallszahlen liegen im Bereich 0 bis RAND_MAX,
0 und RAND_MAX eingeschlossen, das sind also RAND_MAX+1
unterschiedliche Werte.
Um Zufallszahlen im Bereich 0 bis 255 zu generieren (was der OP
vermutlich beabsichtigt) ist also
1
rand()%256
korrekt, wenn
- RAND_MAX=256*n-1 und
- die rand-Funktion das von Rolf Magnus beschriebene Problem nicht
aufweist.
Diese Bedingungen sind zumindest für die glibc und die avr-libc erfüllt.
Andere Frage in diesem Zusammenhang:
Kennt jemand eigentlich eine Methode mit nach oben abschätzbarer
Laufzeit, gleichverteilte Zufallszahlen in "krummen" Intervallen (also
bspw. 0 bis 5) unter Zuhilfenahme der rand-Funktion zu generieren?
Es soll also keine grundlegend neue rand-Funktion entwickelt werden.
Mehrfachaufrufe von rand() sind aber erlaubt, wenn die Anzahl der
erforderlichen Aufrufe eine obere Grenze hat.
yalu wrote:
> Kennt jemand eigentlich eine Methode mit nach oben abschätzbarer> Laufzeit, gleichverteilte Zufallszahlen in "krummen" Intervallen (also> bspw. 0 bis 5) unter Zuhilfenahme der rand-Funktion zu generieren?>> Es soll also keine grundlegend neue rand-Funktion entwickelt werden.> Mehrfachaufrufe von rand() sind aber erlaubt, wenn die Anzahl der> erforderlichen Aufrufe eine obere Grenze hat.
Die Methode die ich aus comp.lang.c++ kenne, funktioniert
so:
Du bestimmst dir das kleinste Vielfache deines n, welches
gerade noch unter MAX_RAND liegt. Dann lässt du mit rand()
eine Zufallszahl generieren und prüfst, ob sie über dieser
Grenze liegt. Wenn ja -> rand() erneut aufrufen und prüfen.
Wenn nein, kannst du ganz normal mit dem % weitermachen wie
gehabt.
Im Grunde verwirfst du einfach alle Zufallszahlen über einer
Grenze, wobei die Grenze so gewählt wurde, dass sie ein Vielfaches
deines interessierenden Bereiches ist.
(Irgendwie bin ich heute nicht in Form. Obige Beschreibung liest
sich grauenhaft. Ich hoffe man kann die Idee dahinter rauslesen)
> (Irgendwie bin ich heute nicht in Form. Obige Beschreibung liest> sich grauenhaft. Ich hoffe man kann die Idee dahinter rauslesen)
Nee, kein Problem, ich habe das sofort verstanden.
So ähnlich mache ich das normalerweise auch, funktioniert ja auch
bestens. Der Schönheitsfehler liegt nur darin, dass (wenn auch mit
geringer Wahrscheinlichkeit) die rand-Funktion u.U. sehr oft
aufgerufen werden muss, bis man einen Wert erhält, der unterhalb der
Grenze liegt.
Deswegen habe ich oben die Forderung nach abschätzbarer Laufzeit bzw.
nach einer oberen Grenze der Anzahl der rand-Aufrufe gegeben. Nur dann
ist die Methode bspw. in Anwendungen mit harten Echtzeitanforderungen
einsetzbar.
Das erscheint irgendwie sinnvoller.
Aber du hast doch gelesen, dass Karl heinz heute nicht so in Form ist.
Und der Leser soll ja auch noch etwas zum mitdenken haben ;-)
kompletten Quellcode wofür?
Wenn du einen Generator für saubere Gleichverteilung in
jedem beliebigen Bereich (natürlich kleiner RAND_MAX + 1)
meinst, dann zb so:
1
intmyRand()
2
{
3
intx;
4
5
while((x=rand())>=RAND_MAX-(RAND_MAX%UpperBound))
6
;
7
returnx%UpperBound;
8
}
Wie und warum das funktioniert, sollte aus den Beschreibungen
von weiter oben eigentlich klar sein.
Wenn deine obere Grenze konstant ist, dann wäre allerdings
diese Version besser, da dann der Compiler einen Teil
der Berechnungen zur Compilezeit erledigen kann