danke, vielleicht habe ich den Baum im Wald nicht gefunden. ;-)
Selbstverständlich hatte ich vorher gesucht, doch immer mit "stdlib" und
da kamen solch einfach Dinge wie
(rand()%(MAX-MIN))+MIN;
nicht vor. (Manchmal muss man wohl suchen lassen :P
D a v i d K. schrieb:> danke, vielleicht habe ich den Baum im Wald nicht gefunden. ;-)> Selbstverständlich hatte ich vorher gesucht, doch immer mit "stdlib" und> da kamen solch einfach Dinge wie>> (rand()%(MAX-MIN))+MIN;>> nicht vor. (Manchmal muss man wohl suchen lassen :P
Das Problem ist, dass dieses hier je nach Werten für MAX und MIN die
Gleichverteilung von rand() zerstört. Bei hinreichend großen Werten für
RANDMAX, und dazu vergleichsweise kleinen Werten für MIN und MAX) ist
das für private Basteleien meistens akzeptabel, weil die Abweichung dann
klein bleibt. Wenn man aber zb bei Spielen eine ordentliche
Gleichverteilung haben will, so dass tatsächlich alle generierten Zahlen
die gleiche Wahrscheinlichkeit haben, dann muss man eben mehr Aufwand
treiben. Du hast ja auch keine Freude, wenn dein Gegenüber einen Würfel
hat, der mit 28%-iger Wahrscheinlichkeit eine 6 würfelt, während die
andere Augenzahlen nur eine 14%-ige Wahrscheinlichkeit haben. Oder?
(Prozentzahlen krass überhöht um das Benutzerproblem zu zeigen)
Wobei man natürlich auch sagen muss, dass die Version vom
Eröffnungsposting schon ausgesprochen schlecht implementiert ist.
Karl Heinz Buchegger schrieb:> Wobei man natürlich auch sagen muss, dass die Version vom> Eröffnungsposting schon ausgesprochen schlecht implementiert ist.
Wesshalb ich sie auch auf keinen Fall so stehen lassen wollte. War halt
nur ein Workarround, damit ich schnell zu einer Ausgabe kam.
Wie "ungleichverteilt" ist denn diese MOD-Methode wirklich?
Wie man sicherlich erkennen kann soll es für eine RAND-Strobo funktion
genutzt werden. Daher ist es mir nur wichtig, dass die Grenzwerte sich
"sichtbar" ändern. Sprich ich möchte keine stufenweise Änderung
erkennen, wenn ich am Poti für MIN MAX spiele.
Grüße Oekel
D a v i d K. schrieb:> Karl Heinz Buchegger schrieb:>>> Wobei man natürlich auch sagen muss, dass die Version vom>> Eröffnungsposting schon ausgesprochen schlecht implementiert ist.>> Wesshalb ich sie auch auf keinen Fall so stehen lassen wollte. War halt> nur ein Workarround, damit ich schnell zu einer Ausgabe kam.>> Wie "ungleichverteilt" ist denn diese MOD-Methode wirklich?
Das hängt von deinen Werten ab.
Nehmen wir mal an, dein Zufallszahlen Generator liefert Werte zwischen 0
und 8 und die sind tatsächlich sauber Normalverteilt. D.h. alle Zahlen
0, 1, 2, 3, 4, 5, 6, 7 haben die gleiche Wahrscheinlichkeit.
Und jetzt versuchst du daraus Zahlen zwischen 0 und 6 zu generieren,
indem du die ursprünglichen 0 .. 8[ mittels MOD 6 in diesen Bereich
'mappst'. Was passiert?
Na schauen wir uns das mal für jede Zahl an, welches Ergebnis entsteht
aus jeder gelieferten Zufallszahl
1
0 wird zu 0
2
1 1
3
2 2
4
3 3
5
4 4
6
5 5
7
6 0
8
7 1
D.h. obwohl du in den Ausgangsdaten (auf statistischen Mengen) gleich
viele 2-er wie 1-er hast, hast du noch der Mod-Rechnung mehr 1-er als
2-er. Denn eine 7 aus den Werten vom Generator wird ja ebenfalls zu
einer 1
Aus dem Generator hatten alle Werte noch die gleiche Wahrscheinlichkeit
von 1/8 = 12.5%
Nach deiner Mod-Umrechnung gibt es immer noch 8 'mögliche' Werte. Aber 2
davon sind jeweils gleich. Von 8 möglichen Ergebnissen sind 2 Stück
davon 1-er. D.h du hast dafür eine Wahrscheinlichkeit von 2/8 = 1/4 =
25%
1
d.h. 0 hat eine Wahrscheinlichkeit von 1/4 oder 25%
2
1 hat eine Wahrscheinlichkeit von 1/4 oder 25%
3
2 hat eine Wahrscheinlichkeit von 1/8 oder 12.5%
4
3 12.5%
5
4 12.5%
6
5 12.5%
Worauf ich bei so einem Würfel mein Geld setzen würde, weiß ich :-)
Jetzt liefert dein Zufallszahlen-Generator natürlich nicht Werte
zwischen 0 und 8 sondern zwischen 0 und RAND_MAX. Und RAND_MAX ist
normalerweise mindestens 32767, was die prozentuale Verschiebung
natürlich um einiges geringer ausfallen lässt. Für den Hausgebrauch
völlig unerheblich, solange MIN und MAX klein sind gegenüber den 32767.
Für eine Spielbank allerdings nicht brauchbar. Denn bei Millionen von
Spielen machen sich auch kleine 'Vorteile' bemerkbar.
(PS: Die Mathematiker nennen diese Problematik das 'Schubladenargument'.
Wenn du n Socken hast, die du in m Schubladen aufteilen musst und n kein
ganzzahliges Vielfaches von m ist, dann bleibt es nicht aus, dass in
manchen Schubladen mehr Socken drinnen sind, als in anderen. Es ist eben
nicht möglich 7 Paar Socken so auf 5 Schubladen zu verteilen, dass in
allen Schubladen gleich viele Paar Socken landen. Mit 15 Paar Socken
würde es gehen. Denn 15 ist ja auch ein ganzzahliges Vielfaches von 5)
nebenbei:
"man rand" liefert folgenden Textabschnitt dazu:
...Bei älteren Implementationen von rand() sind niederwertige Bits
jedoch viel weniger zufällig als höherwertige Bits
In Numerical Recipes in C: The Art of Scientific Computing (William H.
Press, Brian P. Flannery, Saul A. Teukolsky, William T. Vetterling; New
York: Cambridge University Press, 1990 (1st ed, p. 207)), finden sich
die folgenden Kommentare:
"Wenn Sie Zufalls-Ganzzahlen zwischen 1 und 10 erzeugen möchten, sollten
Sie dies immer wie folgt tun:
j=1+(int) (10.0*rand()/(RAND_MAX+1.0));
und niemals auf folgene oder ähnliche Weise:
j=1+((int) (1000000.0*rand()) % 10);
(wodurch niederwertige Bits benutzt würden)."
Zufallszahlenerzeugung ist ein kompliziertes Thema. Das Buch Numerical
Recipes in C (siehe oben) liefert eine exzellente Diskussion über
praktische Zufallszahlenerzeugung in Kapitel 7 (Zufallszahlen).
Hallo,
ich bin gerade unterwegs und habe die Random Funktion eine ewigkeit
nicht mehr verwendet, aber geht es nicht deutlich einfacher so:
1
intMIN=10;
2
intMAX=50;
3
intZUFALL;
4
5
ZUFALL=MIN+(Random()*(MAX-MIN)+1);
ZUFALL sollte dan irgendetwas zwischen 10 und 50 sein.
Random sollte doch eine Zahl >1 zurückliefern die man mit dem
gewünschten Gültigkeitsbereich Multipliziert oder etwa nicht?
Gruß
Deathfun
deathfun schrieb:> ZUFALL = MIN + (Random() * (MAX - MIN) + 1);
Ich weiß nicht, was Random() ist oder wo du das her hast, aber rand()
liefert eine Integer-Zahl im Bereich 0 bis RAND_MAX.
deathfun schrieb:> aber geht es nicht deutlich einfacher so:
naja, "rand()" ist halt seit ewigkeiten in der C-Stdlib (mindestens C89)
und gibt nunmal einen int zurück.
Du hast eine "Random()"-Funktion irgendwoher, die wohl ein float 0..1
o.Ä. ausspucken soll.
Wenn wir also die Standard-Funktionen verlassen, geht es noch einfacher
so:
OH,
Mein Fehler! - könnte (bin mir relativ sicher) Java sein!
Entschuldigt konnte nichts nachschauen, bin unterwegs :(
Dort liefert Random() einen Wert zuwischen 0 und <1 zurück mit dem man
arbeiten kann.
Gruß
Deathfun
deathfun schrieb:> Dort liefert Random() einen Wert zuwischen 0 und <1 zurück mit dem man> arbeiten kann.
.... der in den meisten Implementierungen so entsteht
rand() / (double)RAND_MAX
d.h. du kriegst dort auch nicht mehr als RAND_MAX verschiedene
Zufallszahlen. Nur eben im Bereich 0 bis 1 gelegen und nicht als ganze
Zahlen.
Das Problem ist dadurch immer noch das gleiche. Auch hier greift das
Schubladenargument.
Zufallsverteilungen so umzuformen, dass die Charakteristik der Folge
erhalten bleibt (oder sich gezielt in eine andere verwandelt), ist nicht
so einfach wie es auf den ersten Blick aussieht, wenn man exakt sein
muss.
Hallo,
also ich habe auch das Problem, das ich in reinem C eine gleichverteilte
Zufallszahl (Ganzzahl) benötige, die im Bereich von 1 - 1000 liegen
muss.
Irgendwo habe ich gelesen das man einfach die Rand-Funktion benutzen
kann und Modulo 1024 verwendet. Ziehungen über 1000 werden wiederholt,
was die Laufzeit etwas erhöht, aber kein Problem wäre.
Ist das so korrekt? Und kann jemand kurz einen Codestück posten..
DANKE
Tom
Tom schrieb:> Hallo,>> also ich habe auch das Problem, das ich in reinem C eine gleichverteilte> Zufallszahl (Ganzzahl) benötige, die im Bereich von 1 - 1000 liegen> muss.> Irgendwo habe ich gelesen das man einfach die Rand-Funktion benutzen> kann und Modulo 1024 verwendet. Ziehungen über 1000 werden wiederholt,> was die Laufzeit etwas erhöht, aber kein Problem wäre.
Die Annahme ist hier, dass RAND_MAX ein ganzzahliges Vielfaches von 1024
ist.
> Ist das so korrekt? Und kann jemand kurz einen Codestück posten..
Na komm. Deine textuelle Beschreibung in ein Codestück umzusetzen ist
jetzt aber wirklich nicht das große Problem.
Und nochmal:
Für den Hausgebrauch, für ein kleines Spiel welches unter Freunden
gespielt wird, ist das sehr wahrscheinlich alles ziemlich uninteressant.
Was anderes ist es, wenn es um eine Spielbank geht, bei der Geld im
Spiel ist. Allerdings wird dann höchst wahrscheinlich die Qualität eines
rand() sowieso nicht ausreichend sein.
Also mach dir da jetzt deswegen keine Kopf und nimm einfach
min + rand() % ( max - min )
und gut ists.
PS: Das rand() in den kleineren Bitzahlen keine so guten Werte bringt,
war richtig, wurde meines Wissens aber schon lange korregiert, ist also
heute kein echtes Thema mehr.