Wurf mit zwei Würfeln und Statistische Auswertung
-
Hallo,
ich habe, mal wieder, eine Aufgabe, die ich absolut net hinbekomme.
Einfache Simulation und Analyse von Zufallsereignissen
l Schreiben Sie ein Programm, das simuliert, zwei Würfel 6000mal zu werfen.
l Ergänzen Sie die Simulation um eine Häufigkeitstabelle, die angibt, wie oft die möglichen Augenzahlen eines Wurfes (2 bis 12)
gefallen sind.Das einizige, was mir bis dato eigentlich klar ist, sind die Würfel - zumindest hatte ich das gedacht.
#include <iostream> using namespace std; int main() { int wurf = rand() % 12 + 2; cout << "Sie haben mit zwei Wuerfeln eine: " << wurf << " geworfen."; return 0; }
Ich dachte rand() würde eine zufällige Zahl erzeugen durch modulo 12 bekäme ich eine zahl zwischen 0-10 und müsste halt zwei addieren. Aber pustekuchen. Wie ich das ganze 6000 mal simulieren soll - noch dazu mit statistischer Auswertung - puh keine Ahnung
Kann mir vielleicht erstmal am obigen Code den Denkfehler zeigen und mir nen Tipp geben in welche Richtung ich bei den beiden anderen Sachen gehen muss?
Grüße
Gunnar
-
Hallo,
Bezüglich rand, lies das hier mal
http://www.c-plusplus.net/forum/viewtopic-var-t-is-39344.html
Ansonsten brauchst du halt eine Schleife, die dieses rand 6000mal aufruft. Dann mußt du dir nur noch die Häufigkeit merken. Dazu nimmst du am besten ein int-Array der Größe 10 in dem du deine Würfe hochzählst.
Also irgendwie sowasint zaehler[11]; for( size_t i=0; i<10; ++i) zaehler[i] = 0; for( int i=0; i<6000; ++i) { int wert = 2 + rand() % 11; ++zaehler[wert-2]; }
-
hi hier hast du erst einmal einen kleinen Anreitz um beiden Wuerfeln mit einen wert zu belegen und die augen zu addieren... willst du alles 600 mal machen machst du dies am besten mit einer for-schleife.
#include <ctime> #include <iostream> using namespace std; #pragma hdrstop #pragma argsused int main( int argc, char* argv[] ) { srand( time( 0 ) ); // initialisiert Zufallsgen. mit aktueller zeit // da sich die var der zeit ständig aendert aendert // sich auch immer die zufallszahl int wuerfel_1, wuerfel_2; // unsere 2Würfel int summe; wuerfel_1 = rand() % 6 + 1; // weisst dem wuerfel eine Zufallszahl zw. 1 - 5 zu wuerfel_2 = rand() % 6 + 1; // da auch die null dazu gehört wird der wert noch mal // um 1 erhöht summe = wuerfel_1 + wuerfel_2; // bilde die Summe beider wuerfel cout << " [Zahl] Wuerfel1: " << wuerfel_1 << endl << " [Zahl] Wuerfel2: " << wuerfel_2 << endl << " Summe der Augen: " << summe << endl; getchar(); return 0; }
gruß Tobi :xmas1:
-
Hm....
T0bi ich glaub wenn ich Deins 6000 mal durchlaufen lasse ist die konsole ziemlich zugeplagt ^^.
Die Ausgabe hatte ich ja auch nur einegbaut um überhaupt zu sehen, ob mein Würfel auch wirklich zufällige Zahlen generiert. Ich schätze da ist dein Tipp mit der "initialisierung" (oder nennt man das in dem Zusammenhang dann andres?) schon genau richtig.
Meint ihr es wäre für dieses Programm, mit der Satistik besser 2 Einzelwürfel oder halt ne zufallzahl von 2-12 erstellen zu lassen?
Übrigens würde mich interessieren, wofür folgende Dinge in T0Bi'S Code stehen, weil ich sie nicht zuordnen kann
#pragma hdrstop
#pragma argsused2. int main( int argc, char* argv[] )
demnach ist argc ne Integer zahl und argv nen vector korrekt? mir ist aber nicht klar wofür ich die beiden nun brauche? Sie tauchen ja danach nie wieder auf. ODer haben Sie etwas mit diesem argused zu tun?
Grüße
Gunnar
-
Deswegen sollst du dir auch meinen Code anschauen.
zu 1.
Das ist Borlandspezifisch. Falls du einen anderen Compiler hast kannst du das ignorieren.Das ist eine standardgemäße main-Funktion. Wenn du nicht vor hast deinem Programm in der Kommandozeile irgendwelche Werte zu übergeben, kannst du auch das ignorieren.
In argc steht die Anzahl der übergebenen Argumente.
In argv stehen die übergebenen Argumente.
-
ähmm wollte auch nur anmerken das des mit der count nur zu kontrolle war... die solltest du dann doch schon weg lassen trotzdem kannst du es doch so schreiben:
for( int i = 1; i <= 6000; ++i ) { wuerfel_1 = rand() % 6 + 1; wuerfel_2 = rand() % 6 + 1; summe = wuerfel_1 + wuerfel_2; // so nun weissich ja net aba koennte man es nich mit ner switch machen? switch( summe ) { case 2: ++counter_fuer_2; break; case 3: ++counter_fuer_3; break; case 4: ++counter_fuer_4; break; ... } summe = 0; // um den inhalt von der var wieder zu leeren, muss man glaube aba net } // zum schluss dann alles auf listen cout << "2 Augen" << counter_fuer_2 << endl; ....
koennte man es net so machen?
Gruß Tobi :xmas2: *Rudolf*
-
is umständlich, man kann auch ein couter array erstellen, also int counter[11], dann kann man mit ++counter[Würfel1+Würfel2-2] incrementieren, und nach 6000maligem Ablauf dann auch Ausgeben, indem man eine for-Schleife einsetzt:
... for (int i = 0; i < 6000; i++){ wuerfel1 = rand()/6+1; wuerfel2 = rand()/6+1; ++counter[Würfel1+Würfel2-2]; } for (int i = 2; i <= 12; i++) cout << "Das Ergebnis " << i << " wurde " << counter[i-2] << "mal erreicht." << endl;
Warum an wirklich zwei Würfel nehmen muss, und nicht einfach Eine zufallszahl von zwei bis 12 wählen kann, sieht man, wenn man einmal die Statistik wirklich auswertet, am besten sogar Graphisch: Es kommt dann viel häufiger vor eine sieben zu würfeln, als zum Beispiel eine Zwölf gewürfelt wird, denn dafür gibt es auch viel mehr Möglichkeiten.
-
ähm krux.. ich versteh deinen Ansatz grad überhaupt nicht? wieso setzt du i von 1-12 wonach ja i dem Würfelergebnis der 2 Würfel entspräche?
for (int i = 2; i <= 12; i++)
-
ThaRealMatix schrieb:
Meint ihr es wäre für dieses Programm, mit der Satistik besser 2 Einzelwürfel oder halt ne zufallzahl von 2-12 erstellen zu lassen?
Hallo Gunnar,
es ist nicht dasselbe, ob Du eine gleich-verteilte (!) Zufallszahl zwischen 2 und 12 generierst oder die Summe zweier Zufallszahlen von 1 bis 6. Für letzeres gibt es 36 verschieden Möglichkeiten:
| 1 2 3 4 5 6 --|----------------- 1 | 2 3 4 5 6 7 2 | 3 4 5 6 7 8 3 | 4 5 6 7 8 9 4 | 5 6 7 8 9 10 5 | 6 7 8 9 10 11 6 | 7 8 9 10 11 12
D.h. bei z.B. 396 Würfen von zwei Würfeln hat man im Mittel 11mal eine 2 (1er-Pasch) aber 66mal eine 7. Bei der gleichen Menge von Aufrufen einer Zufallszahl im Intervall [2,12] kommt die 2 und die 7 36mal - also gleich oft vor.
Mit einer Zufalls-Zahl erhält man eine gleichförmige (uniform) Verteilung und mit der Summe zweier Zufalls-Zahlen eine symmetrische Dreiecksverteilung (triangle distribution). siehe auch http://www.boost.org/libs/random/index.htmlGruß
Werner
-
Hallo TheRealMatrix,
für einen Würfel gab's das vor etwa einem Halben Jahr mal von Erhard Henkes.
Hoffe das hilft Dir weiter
Viele Grüße
Knecht
-
Hm...
okay... danke Euch allen erstmal bis hierher
Wenn ich das nun alles so durchsehe, scheint das von T0bi für mich (bezogen auf meinen Wissensstand) die beste Lösung.
Ich schätze mal, dass es auch der praktikabelste Weg ist, das ganze mit einer for schleife 6000 zu simulieren, man müsste halt eine schleife generieren die die Sümme der beiden Würfe wieder auf null setzt nach dem Wurf und neu würfeln lassen.
Aber was ich nicht weiss, ist wie ich die Zufallstabelle machen soll. Man könnte ja die 11 Ergebnisse (2-12) jeweils einmal definieren und dann hochzählen lassen, wenn Sie erreicht werden
also sinngemäß
if (summe ==12) total12++
Das müsste ja gehen, oder? Aber ich würde mal meinen der Code wird ziemlich lang und ineffizient?
-
Pack dir die möglichen Ergebniss besser in ein Array, dann kannst du über den Index darauf zugreifen (wie das gemacht wird, kannst du in Krux' Beitrag sehen - die '-2' dient dazu, den Wertebereich 2..12 auf den für Arrays üblichen Index-Bereich 0..10 umzurechnen).
-
Hm...
okay
also wäre mein code nun:
#include <ctime> #include <iostream> using namespace std; int main() { int wuerfel1; int wuerfel2; int counter[11]; srand( time( 0 ) ); for (int i = 0; i < 6000; i++) { wuerfel1 = rand()/6+1; wuerfel2 = rand()/6+1; ++counter[wuerfel1+wuerfel2-2]; } for (int i = 2; i <= 12; i++) { cout << "Das Ergebnis " << i << " wurde " << counter[i-2] << "mal erreicht." << endl; } }
Was aber nun dazu führt das das Program mit
Wuerfel.exe hat ein Problem festgestellt und muss beendet werden.
crasht
Und wenn ich
wuerfel1 = rand()%6+1; wuerfel2 = rand()%6+1;
nutze wird alles negativ oft erreicht. Aber i ist doch mit 2 initialisiert?
-
Du willst nicht durch 6 teilen sonder den "Rest" haben. Du musst also das "/" durch den Modolo-Operator "%" ersetzen.
[EDIT]Und in deiner zweiten schleife läufts Du über das ende dess arrays hinaus. Da Dein Array nur 11 Stellen groß ist darf Dein Index maximal 10 werden.
-
uhm sorry versteh ich grad nicht? was soll ich ändern
-
Erstmal solltest du jeweils
rand()%6+1
verwenden, dann bleibst du auch im normalen Index-Bereich. Und dann wäre es eventuell eine gute Idee, das Array vor der ersten Schleife mit Nullen zu initialisieren (am einfachsten geht das in der Initialisierung:int counter[11]={0};
Knecht schrieb:
[EDIT]Und in deiner zweiten schleife läufts Du über das ende dess arrays hinaus. Da Dein Array nur 11 Stellen groß ist darf Dein Index maximal 10 werden.
Ne, die Indizes stimmen schon - der letzte Schleifendurchlauf greift auf counter[12-2] == counter[10] zu.
-
Sorry, das hab ich übersehen...
-
er meint, das deine zweite for-Schleife inakzeptabel ist da du das array
counter ja nur mit 11plätzen deklariert hast. also:int counter[11], ist speicherplatz fuer 11 integral variablen.
es soll so ablaufen das du die vorkommenden ereignisse so speicherst:counter[0] // beinhaltet den zählerstand für die 2er
counter[1] // beinhaltet den zählerstand für die 3er
counter[2] // beinhaltet den zählerstand für die 4er
counter[3] // beinhaltet den zählerstand für die 5er
...
counter[10] // beinhaltet den zählerstand für die 12ernun hast du deine ereignisse in das array gepackt. die zahl in den eckigen klammern beinhaltet den index also das "i" um nun in einer for-schleife alle positionen im array an zu sprechen setzt du i = 0, da das erste arrayelement immer array[0] ist. dann erhöhst du es immer um eins, dabei musst du achten das du bei der bedingung in der schleife i < 11 setzt da sonst im fremden speicher gelesen wird, dies hat die folge das dein prog abraucht.
also sieht die schleife so aus:
for( vereinbarung einer variablen; bedingung; was mit der variablen gemacht
werden soll ) {anweisungen!
}for( int i = 0; i < 11; ++i ) { cout << array[i] << endl; }
ich hoffe es ist einigermassen richtig was ich hier jetzt geschrieben habe.
Gruß Tobi :xmas1:
-
ahhh zu spät :D, aber hier haste mal nen prog des funzt ^^
#include <ctime> #include <iomanip> #include <iostream> using namespace std; #pragma hdrstop #pragma argsused int main(int argc, char* argv[]) { int ereigniss[11] = { 0 }; int wuerfel_1 = 0, wuerfel_2 = 0; const int loop = 6000; srand( time( 0 ) ); for( int l = 0; l < loop; ++l ) { wuerfel_1 = rand() % 6 + 1; wuerfel_2 = rand() % 6 + 1; ++ereigniss[ (wuerfel_1 + wuerfel_2) - 2 ]; } cout << " Auswertung der 6000 Wuerfe, die Zahlen 2 - 12 kamen jeweils,\n" << endl; for( int i = 0; i < 11; ++i ) { cout << " Zahl[" << setw( 2 ) << (i + 2) << "] = " << setw( 4 ) << ereigniss[i] << " vor." << endl; } getchar(); return 0; }
Gruß Tobi :xmas2:
-
#include <ctime> #include <cmath> #include <iomanip> #include <iostream> #include <conio.h> using namespace std; int main() { int ereignis[11] = { 0 }; int wuerfel_1 = 0, wuerfel_2 = 0; int LOOP; cout << "Wieviele Versuche? "; cin >> LOOP; srand( time( 0 ) ); for( int l = 0; l < LOOP; ++l ) { wuerfel_1 = rand() % 6 + 1; wuerfel_2 = rand() % 6 + 1; ++ereignis[ (wuerfel_1 + wuerfel_2) - 2 ]; } cout << "\nAuswertung der " << LOOP << " Wuerfe. Die Zahlen 2 - 12 kamen\n" << endl; for( int i = 0; i < 11; ++i ) { cout << " Zahl[" << setw( 2 ) << (i + 2) << "] = " << setw( log(LOOP)/2.0 ) << ereignis[i] << " vor." << endl; } getch(); }