rand() mit min max

Persönliche Seite #3209551
Lesenswert?

Hi,
1
strobo_counterOFF = rand();
2
while(strobo_counterOFF < out_stroboRD_MIN || strobo_counterOFF > out_stroboRD_MAX)
3
     strobo_counterOFF = rand();

Das geht doch bestimmt noch eleganter, oder?
Möchte außer der stdlib nicht unnötig viel nur für diesen einen Fall 
einbinden.

Grüße Oekel
#3209762
Lesenswert?

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.
Persönliche Seite #3209797
Lesenswert?

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
#3209834
Lesenswert?

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)
#3214506
Lesenswert?

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).
Gast #3214534
Lesenswert?

Hallo,

ich bin gerade unterwegs und habe die Random Funktion eine ewigkeit 
nicht mehr verwendet, aber geht es nicht deutlich einfacher so:
1
int MIN = 10;
2
int MAX = 50;
3
int ZUFALL;
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
#3214564
Lesenswert?

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:
1
int ergebniss=erzeugeGleichverteilteZufallszahlAlsInteger(MIN,MAX);

Implementation der Funktion als Übungsaufgabe für den geneigten Leser ;)

in C++:
1
std::default_random_engine generator;
2
std::uniform_int_distribution<int> distribution(1,6);
3
int dice_roll = distribution(generator);  // generates number in the range 1..6
Gast #3214578
Lesenswert?

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
#3214618
Lesenswert?

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.
Gast #3214781
Lesenswert?

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
#3214858
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren