Hallo zusammen, ich suche eine Funktion, die mir eine Zufallszahl (unsigned char) generiert und dabei die gleichmäßige Verteilung gewährleistet wird. Es sollen dabei die Grenzen vorgegeben werden können. (z.B. 0 bis 3 und 0 bis 255). Ich habe nun schon über mehrere Möglichkeiten gelesen. Nach Aussage sollte die nachfolgende Funktion die gleichmäßige Verteilung gewährleisten: int rand_stat( int a, int e) { double r = e - a + 1; return a + (int)(r * rand()/(RAND_MAX+1.0)); } Kann die Funktion dafür eingesetzt werden? Warum muss r als double deklariert werden? Kann ich diese auch für Zahlen im Format unsigned char umschreiben? Könnte mir jemand die Funktion in ein paar Sätze erklären? Ich danke Euch im Voraus. Schönen Abend noch
SlideR schrieb: > Kann die Funktion dafür eingesetzt werden? Nein. Da hilft auch der double nichts. Da kommt das sog. Schubladen Argument ins Spiel: Es ist unmöglich n Paar Socken in m Schubladen zu legen, so dass in allen Schubladen gleich viele Socken liegen, solange m nicht ein ganzzahliges Vielfaches von n ist. D.h. Wenn du 5 Schubladen hast, kannst du nur 5, 10, 15, 20, .... Paar Socken da drinnen gleichmässig verteilen. Bei allen anderen Zahlen wird es IMMER (egal was du machst) so sein, dass in einigen Schubladen mehr und in anderen Schubladen weniger Socken enthalten sind. Die Umrechnung auf double bringt dabei genau gar nichts. Denn auch dann ist es ja so, dass sich die Anzahl der Zahlen die aus aus r * rand()/(RAND_MAX+1.0) entstehen können, nicht erhöht. Ob ich jetzt die Zahlen 0, 1, 2, 3, 4, 5 habe, oder 0.0, 0.1, 0.2, 0.3, 0.4, 0.5 oder 0.00, 0.05, 0.10, 0.15, 0.20, 0.25 ändert nichts daran, dass ich nur 5 verschiedene Zahlen erzeugt habe. Sie haben einen anderen Wertebereich, ja. Aber es sind deswegen (von der Anzahl her) nicht mehr oder weniger. Die einzige Chance, wenn man genau sein will, ist es, einige der Paar Socken nicht einzusortieren. Sind 5 Schubladen verfügbar und muss ich 30001 paar Socken einsortieren, dann werden in 4 Schubladen 6000 Paar Socken liegen und in einer 6001. -> keine Gleichverteilung. Welche diese Lade mit dem 1 Paar mehr ist, kann ich durch eine Umnummerierung der Socken steuern, aber ich kann das grundsätzliche Problem der fehlenden Gleichverteilung damit nicht beheben. Nur dadurch, dass ich 1 Paar zur Seite legen und aus den 30001 genau 30000 Paar mache (einem Vielfachen von 5), gelingt es in allen Laden gleich viele Socken zu haben. > Könnte mir jemand die Funktion in ein paar Sätze erklären? Die angedachte Funktion kannst du dir selbst ganz leicht erklären. Denk dir ein paar Zahlen zwischen 0 und 10 aus. zb 5 3 8 7 2 Wie kannst du jetzt aus diesen Zahlen die dem Prinzip nach gleiche Zahlenreihe zwischen 40 und 50 erzeugen? Ganz einfach: Indem du zu den Zahlen, die du dir ausgedacht hast einfach 40 dazuzählst. 45 43 48 47 42 Wie kannst du mit deinen ursprünglichen Zahlen von 1 bis 10 eine dem Prinzip nach gleiche Zahlenreihe von 40 bis 60 erzeugen? Ganez einfach: Nimm alle Zahlen mal 2 (warum gerade 2?), dann hast du Zahlen von 0 bis 20. 10 6 16 14 4 Und wenn du dann noch 40 dazuzählst, dann hast du Zahlen im Bereich 40 bis 60. 50 46 56 54 44 Und jetzt siehst du mal in deiner Funktion nach, was du da wieder findest.
Vielen Dank für die super Erklärung, echt genial! Bringt die Funktion denn einen Unterschied zum einfachen Modulo Operator? Beispiel rand()%3 ? Gibt es eine andere Möglichkeit Zahlen zu generieren, ohne dass bei einem kleinen Zahlenbereich z.B. 0 bis 2 die 0 "viel" öfter vorkommt als die 1 und 2? Gruß
> die 0 "viel" öfter vorkommt als >die 1 und 2? wie kommst du auf die idee, dass das passiert ?? Karl Heinz Buchegger ist da nur etwas zu "kleinlich" es geht ja schließlich um Zufallszahlen, da "müssen" in manchen Schubladen mal mehr mal weniger Socken sein...
Wenn ich zum Bsp. rand() % 6 habe generiert er mir zahlen zwischen 0 und 1, aber die 0 und 1 kommt öfter vor: Zahl von rand() % 6 0 0 1 1 2 2 3 3 4 4 5 5 6 0 7 1 Nun suche ich nach einer Methode mit der ich dieses Problem umgehe. Gerade bei kleinen Wertebereichen wirkt sich dieses negativ auf die gleichmäßige Verteilung aus. Was kann ich dagegen machen?
SlideR schrieb: > Was kann ich dagegen machen? Ein System wählen bei dem RAND_MAX nicht nur 7 ist...? Lies doch einfach mal was geschrieben wurde, wie willst du bei deinem Beispiel den die übrigen zwei Werte "gleichmäßiger" verteilen?
Ich stehe gerade aufm Schlauch, sorry. Aus diesem Grund bitte ich um Hilfe! Wenn ich das nun richtig verstanden habe, kann ich die funktion: int rand_stat( int a, int e) { double r = e - a + 1; return a + (int)(r * rand()/(RAND_MAX+1.0)); } verwenden und wie kann ich nun RAND_MAX beeinflussen? Sorry, aber ich komme gerade nicht mehr hinterher :)
Was sie dir sagen wollen > Ein System wählen bei dem RAND_MAX nicht nur 7 ist...? > Karl Heinz Buchegger ist da nur etwas zu "kleinlich" Klär doch erst mal ab, ob das für deine konkrete Aufgabenstellung ein Problem ist. Dein konkretes rand hat ein RAND_MAX von 32767 oder höher. Ein damit naiv implementierter Würfel rand() % 6 hat die Verteilung 0: 5462 1: 5461 2: 5461 3: 5461 4: 5461 5: 5461 d.h. die 0 kommt ein kleines bischen zu häufig vor. Allerdings nicht sehr viel. Für eine Spielbank wäre das inakzeptabel. Da gehts aber auch um sehr viel Geld. Für ein privates Mensch-ärgere-dich-nicht spielt die kleine Abweichung allerdings praktisch gesehen keine Rolle. Wenn dir das nicht reicht, dann musst du eben 'überzählige Socken verwerfen'. Du rechnest dir aus, welches die größte Zahl ist, die rand() noch bringen darf und alles was größer ist, wird verworfen maxFaktor = RAND_MAX / 6; // 6 wegen dem Würfel maxRand = maxFaktor * 6; .... do { x = rand(); } while( x > maxRand ); return x % 6; Die Sache mit den Socken hab ich deswegen aufs Tapet gebracht, weil man immer wieder Web-Seiten sieht, die eine derartige Rumrechnerei veranstalten, mit dem Hinweis, das dadurch die Gleichverteilung wieder hergestellt werden solle. Jetzt weißt du, das das Humbug ist und du kennst auch das Argument, mit dem du diesem Humbug entgegen treten kannst. Es gibt keine Möglichkeit, durch eine simple Umrechnerei eine exakte Gleichverteilung herzustellen, wenn der Generator ganze Zahlen liefert und der Wertebereich des Generators kein Vielfaches des Wertebereichs der Zielverteilung ist. Ob das ein Problem ist, muss jeder für sich und anhand seiner Aufgabenstellung entscheiden. Denn was ja auch nicht vergessen werden darf: Bei rand() haben wir es mit Pseudozufallszahlen zu tun. D.h. alleine schon deshalb wird auch der nie (bei großen Anzahlen von generierten Zahlen) eine exakte Gleichverteilung liefern.
>ich suche eine Funktion, die mir eine Zufallszahl (unsigned char) >generiert und dabei die gleichmäßige Verteilung gewährleistet wird. Muss es rand() sein? Ansonten kannst du dir die Boost oder C++11 Random Library man anschauen.
Karl Heinz Buchegger schrieb: > Denn was ja auch nicht vergessen werden darf: Bei rand() haben wir es > mit Pseudozufallszahlen zu tun. D.h. alleine schon deshalb wird auch der > nie (bei großen Anzahlen von generierten Zahlen) eine exakte > Gleichverteilung liefern. Ich würde sagen, umgekehrt wird ein Schuh draus: Ein guter, gleichverteilter Pseudozufallszahlengenerator sollte spätestens wenn er einmal komplett durchlaufen wurde, auch wirklich exakt gleiche Häufigkeiten für die Zahlen geliefert haben. Bei echten Zufallszahlen ist es Teil des Zufalls, daß die Häufigkeiten praktisch nie exakt übereinstimmen. Dafür sind es aber jedes Mal andere Zahlen, deren Häufigkeit etwas nach oben oder unten abweicht.
Vielen Dank für Eure Antworten. Karl Heinz Buchegger, danke nun habe ich es auch verstanden. :) Nein, es muss nicht unbedingt die rand()-Funktion sein.
Karl Heinz Buchegger schrieb: > d.h. die 0 kommt ein kleines bischen zu häufig vor. Allerdings nicht > sehr viel. Ja, in aller Regel wird man mit modulo gut hinkommen. Wenn man ganz kleinlich ist, kann man ja den von rand() gelieferten Wert erst ansehen. Ist er größer oder gleich als der größte glatt teilbare Werte unterhalb RAND_MAX (also bei 32767 für RAND_MAX und Wunschwerten 0...6 wäre das bei >=32767), verwirft man den Wert einfach und holt sich mit rand() den nächsten, bis man einen hat der kleienr ist. Nimmt man den modulo 7 (in diesem Fall), hat man wirklich eine Gleichverteilung.
Ich sitze vor dem selben Problem wie der Autor "SlideR". Ich möchte einen Zufallsgenerator programmieren, dieser soll die untere Grenze und die obere Grenze übergeben bekommen und mir die Zufallszahl als Rückgabewert liefern. Bisher habe ich folgendes erreicht:
1 | unsigned char rand_stati(const unsigned char lower_range, const unsigned char upper_range) |
2 | {
|
3 | |
4 | unsigned char range,help,help1; |
5 | |
6 | range = upper_range-lower_range; |
7 | help = RAND_MAX - (RAND_MAX % range); |
8 | |
9 | do
|
10 | {
|
11 | help1 = rand(); |
12 | }while (help1 < help); |
13 | |
14 | return (help1 % range) + lower_range; |
15 | }
|
zusätzlich generiere ich mir vor jedem Programmaufruf einen random Startwert mit srand(). srand() bekommt eine integer Wert übergeben. Kann das alles so funktionieren? Ich bin mit einem "Programmierkünsten" leider am Ende angekommen und bitte Euch um Hilfe.
Rafael schrieb: Nachdenken. > do > { > help1 = rand(); > }while (help1 < help); wieso "kleiner"? > zusätzlich generiere ich mir vor jedem Programmaufruf einen random > Startwert mit srand(). srand() bekommt eine integer Wert übergeben. Ich hoffe du meinst damit: Du rufst srand() EIN EINZIGES MAL beim Programmstart auf. srand() vor jedem Aufruf von rand() aufzurufen ist absolut kontraproduktiv und definitiv nicht das was du machen willst. Damit rand() eine gleichverteilte Zufallsfolge generieren kann ist es unabdingbar, dass es in Ruhe arbeiten kann, OHNE dass du dauernd mit srand() dazwischenfunkst. > Kann das alles so funktionieren? Ich bin mit einem "Programmierkünsten" > leider am Ende angekommen und bitte Euch um Hilfe. Geh deinen Programmtext einfach mit ein paar Zahlen durch und simuliere (also: du spielst Computer) dein Programm. Passiert das, was du möchtest?
Karl Heinz Buchegger schrieb: > Nachdenken. > >> do >> { >> help1 = rand(); >> }while (help1 < help); > > wieso "kleiner"? Ich werde das Programm nochmal durchgehen, vielleicht ist mir da doch ein Fehler unterlaufen. Danke für den Tipp. Karl Heinz Buchegger schrieb: > Du rufst srand() EIN EINZIGES MAL beim Programmstart auf. > srand() vor jedem Aufruf von rand() aufzurufen ist absolut > kontraproduktiv und definitiv nicht das was du machen willst. Damit > rand() eine gleichverteilte Zufallsfolge generieren kann ist es > unabdingbar, dass es in Ruhe arbeiten kann, OHNE dass du dauernd mit > srand() dazwischenfunkst. Ich rufe srand() vor jedem Programmdurchlauf auf, jedoch übergebe ich srand() einen über ein Timer generierten Wert, so habe ich ca. 65 000 unterschiedliche Startwerte. Reicht das so etwa nicht? Sollte ich srand() wirklich nur einmal im Programm aufrufen?
Rafael schrieb: > Sollte ich > srand() wirklich nur einmal im Programm aufrufen? ja! Am besten direkt am Anfang in der Initialisierung. am besten ein einmaliges srand(time(0)); wenn du während der Entwicklung reproduzierbarkeit wünschst (was meistens eine gute Idee ist) kannst du auch eine fixe kosntante angeben, da bekommst du immer die selbe "Zufalls"zahlen-Folge.
Wobei man dann auch gar kein srand() braucht ... Daher die Frage, ob es hier überhaupt Sinn macht.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.