Zufallszahl erzeugen (und weitere kleine Fragen)
-
Hallo alle zusammen,
bin neu hier im Forum und hoffe ihr könnt mir ein wenig helfen.
Ich hatte meinen C-Kurs für Einsteiger vor 3 Jahren gehabt und muss aber jetzt wieder Kleinigkeiten programmieren.Hat bisher auch mit den Basics ganz gut geklappt, aber mir fehlt das Wissen einfach von damals.
Doch vorallem habe ich nicht herausfinden können wie man Zufallszahlen generiert. Bzw gabs verschiedene Quellen bei Google, aber entweder konnte ich es nicht anwenden oder es hat nicht das gegeben was ich wollte.
1.) Und zwar brauche ich eine Zufallszahl zwischen 0 und 1 ("inklusive" den beiden, was aber ja eigtl "unmöglich" ist).
Das was ich bisher benutzt habe dann im Programm ist:
#include <stdio.h> #include <stdlib.h> int main() { float p; p = rand() / ((double)RAND_MAX + 1); return 0; }
Jetzt habe ich aber bemerkt, dass ich hier immer dieselbe Zufallszahl erzeuge. Ich habe auch später das selbe benutzt in einer for-Schleife und habe mir 10 Zufallszahlen ausgeben lassen. Doch in jeder Runde kommen immer dieselben 10 Zufallszahlen.
Ich habe in der Uni damals srand benutzt, aber irgendwie hier beim anwenden hats gar nicht geklappt...
Um das richtig zu verstehen, gibt es z.B. auch eine Möglichkeit eine Zufallszahl von 0 bis 100, oder sogar 12 bis 100 zu erzeugen?
2.) Der nächste Code bereitet mir auch Probleme
#include <stdio.h> #include <stdlib.h> int main() { float p; p = rand() / ((double)RAND_MAX + 1); printf("Kopfwahrscheinlichkeit %f\n", p); if(p < 1/2){ p = 1-p; } float q; q = 1-p; printf("Gewinnwkeit %f\n", p); return 0; }
Was ich hier programmieren will ist ein Münzwurfspiel. Zuerst soll uns der Generator eine Zufallszahl für "Kopf" geben zwischen 0 und 1.
Dann kommen paar Schritte die ich weggelassen habe. Der "Spieler" wird ja natürlich nur Kopf wählen wenn p > 1/2 ist. Deswegen habe ich die if Schleife reingetan, damit wenn die Kopfwkeit kleiner als 1/2 ist wir Zahl wählen (aber die Variable p behalten). Deswegen p = 1 - p gesetzt.
Doch wenn ich diesen Code bei mir mache, bleibt p nach der if-Klausel immer noch das alte p.In meinem Beispiel hat der Zufallsgenerator p = 0.001251 gegeben und danach beim zweiten printf gibt er mir wieder 0.001251 obwohl es ja 0.998749 sein müsste. Könnt ihr den Fehler erkennen?
_________________________Darf ich auch noch ein paar kleine andere Fragen stellen:
3.) Gibt es eigentlich bei Integern eine Grenze?
D.h. wenn ich z.B. eine neue Zahl k erzeuge die die Summe von 100 integern ist.?4.) Bei Kommazahlen benutze ich float. Da hat letztens eine Kommilitonin gemeint, dass sie was anderes benutzt. Was würdet ihr da empfehlen?
5.) Bei den float-Zahlen. Gibt es ne Möglichkeit das auf 3 Nachkommastellen runden zu lassen (im granzen Programm?).
6.) Gibt es auch Grenzen beim Programm selbst. Ich wollte z.B. einen array mit Länge 10.000 erzeugen und diese dann mit Zufallsvariablen zwischen 0 und 1 besetzen (durch eine for Schleife). Das hat aber nicht funktioniert. Lag es an der Länge?
7.) Warum geben beide for-Schleifen das selbe raus? Gabs da nicht ein Unterschied zwischen ++i und i++?
#include <stdio.h> #include <stdlib.h> int main() { int i; for(i = 1; i < 10; i++){ printf("%d, ",i); } for(i = 1; i < 10; ++i){ printf("%d, ",i); return 0; }
-
wima_carsi38 schrieb:
Ich habe in der Uni damals srand benutzt, aber irgendwie hier beim anwenden hats gar nicht geklappt...
Dann zeig doch das, was nicht geklappt hat! Wie sollen wir dir sonst helfen? srand ist schon richtig. Das benutzt du einmal am Programmanfang. Natürlich muss der Initialwert jedes mal eine andere Zahl sein, sonst bekäme man ja immer noch immer die gleiche Zufallszahlenfolge. Da kann man beispielsweise die Uhrzeit nehmen (ist aber meistens nur sekundengenau):
srand(time(NULL));
Um das richtig zu verstehen, gibt es z.B. auch eine Möglichkeit eine Zufallszahl von 0 bis 100, oder sogar 12 bis 100 zu erzeugen?
Jain. srand erzeugt (ganze!) Zufallszahlen zwischen 0 und RAND_MAX (Grenzen inklusive). Überleg mal, wie man von da aus auf andere Bereiche umrechnen kann.
if Schleife
Doch wenn ich diesen Code bei mir mache, bleibt p nach der if-Klausel immer noch das alte p.
Wie viel ist denn 1/2? (Tipp: Die Antwort ist nicht 0.5)
3.) Gibt es eigentlich bei Integern eine Grenze?
Ja.
4.) Bei Kommazahlen benutze ich float. Da hat letztens eine Kommilitonin gemeint, dass sie was anderes benutzt. Was würdet ihr da empfehlen?
double.
Und ob eine Zahl ein Komma hat oder nicht, ist nicht das Kriterium. Integer für diskrete Zahlenwerte, Fließkommazahlen für kontinuierliche Größen. Das ist der Unterschied.5.) Bei den float-Zahlen. Gibt es ne Möglichkeit das auf 3 Nachkommastellen runden zu lassen (im granzen Programm?).
Nein. Wieso sollte man jemals so etwas wollen?
Erklär mal, warum du das möchtest. Möchtest du nur die Ausgaben auf 3 Stellen beschränken? Wenn ja: Klar geht das.6.) Gibt es auch Grenzen beim Programm selbst.
Ja.
Ich wollte z.B. einen array mit Länge 10.000 erzeugen und diese dann mit Zufallsvariablen zwischen 0 und 1 besetzen (durch eine for Schleife). Das hat aber nicht funktioniert. Lag es an der Länge?
Das ist eher unwahrscheinlich. Wieder: Wenn du Fehler hast, reicht es nicht, wenn du uns bloß sagst, dass irgendein geheimer Fehler bei irgendwelchem geheimen Code aufgetreten ist. Wie soll man dir da helfen?
7.) Warum geben beide for-Schleifen das selbe raus? Gabs da nicht ein Unterschied zwischen ++i und i++?
Ja, da gibt es einen Unterschied. Erklär ihn doch mal. Und dann sollte auch klar sein, warum hier der Unterschied nichts ausmacht.
-
Das sind alles nur Pseudozufallszahlen, dessen Generator du jedes mal neu initialisieren musst, am besten mit time oder so. Lies dich am besten mal in das Thema ein.
-
- Der Pseudozufallsgenerator erzeugt Zahlen zwischen 0 und RAND_MAX
Daher ist es durchaus möglich Zahlen zwischen 0 und 1 "inklusive" zu erzeugen:
p = rand() / (double)RAND_MAX;
Wegen
srand
schau mal bei http://www.cplusplus.com/reference/cstdlib/srand/- 1/2 ist eine Integerdivision und die ergibt 0 (1 geteilt durch 2 ist 0 Rest 1)
Du willst entweder 1.0/2 oder gleich 0.5
Wobei ein
rand() % 2
für einen Münzwurf ausreicht. Das ergibt 0 oder 1.Nebenbei: if-Schleifen gibt es nicht: http://www.if-schleife.de/
-
Ja. siehe http://www.cplusplus.com/reference/climits/
Beachte abe,r dass das Mindestangaben sind. Die tatsächlichen Grenzen bei deinem Compiler können (werden) anders sein. -
double
(oderint
odersize_t
oder ... . Was gerade sinnvoll ist.)
5)Du kannst es bei der Ausgabe mit printf machen.
-
Jein. Von C her nicht, aber die realen Implementierungen haben da schon Grenzen.
Wo die liegen hängt aber vom System ab. -
Ja, den Unterschied gibt es. Aber nur, wenn du zu dem Zeitpunkt auch etwas mit i machst (auslesen).
#include <stdio.h> int main() { int i; for(i = 1; i < 10; ){ printf("%d, ",i++); } for(i = 1; i < 10;){ printf("%d, ",++i); return 0; }
- Der Pseudozufallsgenerator erzeugt Zahlen zwischen 0 und RAND_MAX
-
Erstmal Danke an euch beide für die Antworten.
SeppJ schrieb:
Dann zeig doch das, was nicht geklappt hat! Wie sollen wir dir sonst helfen? srand ist schon richtig. Das benutzt du einmal am Programmanfang. Natürlich muss der Initialwert jedes mal eine andere Zahl sein, sonst bekäme man ja immer noch immer die gleiche Zufallszahlenfolge. Da kann man beispielsweise die Uhrzeit nehmen (ist aber meistens nur sekundengenau): srand(time(NULL));
Ich sitze seit mehreren Tagen am Programmieren und es haben sich Fragen gestapelt. Kann mich nicht mehr an alles erinnern, was damals nicht funktioniert hat. In dem Falle war es gewesen, dass es nur Beispiele für z.B. Würfeln gab. Ohne Erklärung ohne gar nix. Deswegen habe ich das nicht verstanden. Ich hoffte auf eine gute Erklärung hier.
Verstehe ich jetzt richtig, dass ich wenn ich eine Zufallszahl erzeugen will z.B. zwischen 11 und 100 ich dann den Code
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int t; srand(time(NULL)); t = 11 + rand()%100); }
benutzen muss??? Ist hier dann die Zufallszahl im Intervall von 11 bis 100?
Kann mir jemand erklären warum p = rand() / (double)RAND_MAX; eine Zufallszahl zwischen 0 und 1 gibt? Ich hab das ehrlich gesagt damals nur mit Copy und Paste benutzt.SeppJ schrieb:
double.
Und ob eine Zahl ein Komma hat oder nicht, ist nicht das Kriterium. Integer für diskrete Zahlenwerte, Fließkommazahlen für kontinuierliche Größen. Das ist der Unterschied.Was sind denn die Vorteile von double zu float?
SeppJ schrieb:
Nein. Wieso sollte man jemals so etwas wollen?
Erklär mal, warum du das möchtest. Möchtest du nur die Ausgaben auf 3 Stellen beschränken? Wenn ja: Klar geht das.Es war etwas schlecht ausgedrückt. Will es ja nicht beschränken, sondern nur bei der Ausgabe. Habe aber bisher nur einen eigenen aber schlechten Weg gefunden. Wenn ich eine Zahl x auf 3 Nachkommastellen runden will, kann ich einfach y = round(x*1000); machen und dann y ausgeben.
Doch ist das nicht zu umständlich? Wenn ich jetzt 20 Variablen habe, x,y,z,Ziel,Schranke etc dann müsste ich das bei jedem einzeln machen.Ich habe dank eurem Hinweis von printf glaube ich den richtigen Weg gefunden.
Wenn ich eine float-Zahl x habe, dann kann ich die auf zwei Nachkommastellen mit printf("%.2f", x); ausgeben. Das ist der richtige Weg oder?SeppJ schrieb:
Das ist eher unwahrscheinlich. Wieder: Wenn du Fehler hast, reicht es nicht, wenn du uns bloß sagst, dass irgendein geheimer Fehler bei irgendwelchem geheimen Code aufgetreten ist. Wie soll man dir da helfen?
OK, beim nächsten mal schreibe ich es auf. Dieser Fehler ist mir halt nur aufgefallen und ich wollte es fragen. Ich habe dann einfach dann weiterprobiert und habe halt die "alten" Ergebnisse nicht. Ich habe dann statt einem n[100000] einen array n[1000] benutzt. Und dann ging das Programm plötzlich.
SeppJ schrieb:
Ja, da gibt es einen Unterschied. Erklär ihn doch mal. Und dann sollte auch klar sein, warum hier der Unterschied nichts ausmacht.
Leider kenne ich den Unterschied nicht. Ich habe wie gesagt vor über zwei Jahren das letzte mal einen Einführungskurs gehabt. Deswegen habe ich den Code (erster Beitrag) probiert um zu schauen ob es ein Unterschied gibt. Bei meinem Code gabs keinen...Ich weiß den Unterschied nicht, deswegen kann ich ihn dir nicht sagen.
___________________________________________DirkB schrieb:
Der Pseudozufallsgenerator erzeugt Zahlen zwischen 0 und RAND_MAX
Daher ist es durchaus möglich Zahlen zwischen 0 und 1 "inklusive" zu erzeugen:Kannst du dir mein Problem oben anschauen wo ich Seppj geantwortet habe?
DirkB schrieb:
- 1/2 ist eine Integerdivision und die ergibt 0 (1 geteilt durch 2 ist 0 Rest 1)
Du willst entweder 1.0/2 oder gleich 0.5
Danke
DirkB schrieb:
Beachte abe,r dass das Mindestangaben sind. Die tatsächlichen Grenzen bei deinem Compiler können (werden) anders sein.
Danke. So wie ich es verstehe, sollte ich dann lieber long benutzen statt int oder? Hat long irgendeinen Nachteil statt int?
DirkB schrieb:
double
(oder int oder size_t oder ... . Was gerade sinnvoll ist.)Woher weiß ich denn, was gerade sinnvoll ist?
DirkB schrieb:
5)Du kannst es bei der Ausgabe mit printf machen.
Ich habe dank eurem Hinweis von printf glaube ich den richtigen Weg gefunden.
Wenn ich eine float-Zahl x habe, dann kann ich die auf zwei Nachkommastellen mit printf("%.2f", x); ausgeben. Das ist der richtige Weg oder?DirkB schrieb:
- Ja, den Unterschied gibt es. Aber nur, wenn du zu dem Zeitpunkt auch etwas mit i machst (auslesen).
Würde es dir ausmachen, ein klitzekleines Beispiel mir dafür zu nennen?
_______________________1.) Jetzt habe ich ein Problem. Ich habe das mit srand und time benutzt, damit ich bei jeder Implementierung, dann eine neue Zufallsvariable bekomme. Nur ist jetzt das Problem, wenn ich ziemlich schnell hintereinander klicke, sind die Zufallsvariablen ziemlich nahe beieinander.
2.)
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int j; for(j = 1; j <= 5; ++j){ float n[10]; srand(time(NULL)); int i; for(i=1; i <= 10; ++i){ n[i] = rand() / ((double)RAND_MAX + 1); printf("%f", n[i]); } printf("\n"); } return 0; }
Was ich hier programmieren wollte:
Ich will mir fünf arrays der Länge 10 ausgeben lassen die durch Zufallszahlen zwischen 0 und 1 besetzt sind.Doch was macht mein Code:
Er gibt nur ein einziges array aus.
Was habe ich denn falsch gemacht? Ich meine ich habe ja "j" benutzt und nicht zweimal "i" in den for-Schleifen.Und nochmals Danke
Viele Grüße
wima
- 1/2 ist eine Integerdivision und die ergibt 0 (1 geteilt durch 2 ist 0 Rest 1)
-
wima_carsi38 schrieb:
Verstehe ich jetzt richtig, dass ich wenn ich eine Zufallszahl erzeugen will z.B. zwischen 11 und 100 ich dann den Code
#include <stdio.h> #include <stdlib.h> #include <time.h> int main() { int t; srand(time(NULL)); t = 11 + rand()%100); }
benutzen muss??? Ist hier dann die Zufallszahl im Intervall von 11 bis 100?
Das ergibt ein Intervall von 11 bis 110 (inklusive)
Mit dem % 100 (Modulo 100) bekommst du den Rest der Division durch 100 (3. Klasse). Der kann im Bereich von 0 bis 99 sein. Dazu werden noch 11 addiert.wima_carsi38 schrieb:
Kann mir jemand erklären warum p = rand() / (double)RAND_MAX; eine Zufallszahl zwischen 0 und 1 gibt? Ich hab das ehrlich gesagt damals nur mit Copy und Paste benutzt.
Nehmen wir mal an
RAND_MAX
ist 32767 und rand() liefert dir 0. Was kommt bei der Rechnung aus.
Oder rand() liefert 32767. Was kommt dann raus?wima_carsi38 schrieb:
Was sind denn die Vorteile von double zu float?
Höhere Genauigkeit und größerer Wertebereich.
Ein Nachteil ist der größere Speicherverbrauch, der aber nur bei sehr, sehr großen Arrays eine Rolle spielt.wima_carsi38 schrieb:
So wie ich es verstehe, sollte ich dann lieber long benutzen statt int oder?
Nein.
wima_carsi38 schrieb:
Hat long irgendeinen Nachteil statt int?
Mehr Speicherverbruach, dadurch längere Verarbeitungszeit. Aber auf manchen Systemen sind sie identisch, daher stimmt da die Aussage nicht.
wima_carsi38 schrieb:
Würde es dir ausmachen, ein klitzekleines Beispiel mir dafür zu nennen?
Hast du denn mein abgewandeltes Beispiel mal ausgeführt?
Beim Preinkrement wird der Wert der Variablen vor dem Inkrement genommen.
Beim Postinkrement wird der Wert der Variablen nach dem Inkrement genommen._______________________
wima_carsi38 schrieb:
1.) Jetzt habe ich ein Problem. Ich habe das mit srand und time benutzt, damit ich bei jeder Implementierung, dann eine neue Zufallsvariable bekomme. Nur ist jetzt das Problem, wenn ich ziemlich schnell hintereinander klicke, sind die Zufallsvariablen ziemlich nahe beieinander.
Das
srand
sollte nur einmal im ganzen Programm aufgerufen werden.
Du rufst es aber fünfmal auf.wima_carsi38 schrieb:
Ich will mir fünf arrays der Länge 10 ausgeben lassen die durch Zufallszahlen zwischen 0 und 1 besetzt sind.
Du hast ein Array, das fünmal neu beschrieben wird.
Für das Array n bietet sich hier int an (oder sogar char), da du nur 2 (diskrete) Werte darin ablegen willst.
Undn[i] = rand() %2;
macht das eleganter.Nebenbei solltest du an deinem Einrückungsstil arbeiten: https://de.wikipedia.org/wiki/Einrückungsstil
-
@DirkB: Danke für die Antworten
DirkB schrieb:
Das ergibt ein Intervall von 11 bis 110 (inklusive)
Mit dem % 100 (Modulo 100) bekommst du den Rest der Division durch 100 (3. Klasse). Der kann im Bereich von 0 bis 99 sein. Dazu werden noch 11 addiert.Danke jetzt habe ich das verstanden.
DirkB schrieb:
Nehmen wir mal an RAND_MAX ist 32767 und rand() liefert dir 0. Was kommt bei der Rechnung aus.
Oder rand() liefert 32767. Was kommt dann raus?Super auch das habe ich nun verstanden. Ich habe das "geteilt" ganz anders aufgefasst :(. Also rand() hat gibt uns ja eine Zufallszahl zwischen 0 und 32767 wenn ich das richtig verstehe. Und wenn man jetzt das ganze durch 32767 teilt entsteht somit ein Intervall zwischen 0 und 1.
Kannst du mir nur bestätigen ob ich das richtig verstanden habe?DirkB schrieb:
Höhere Genauigkeit und größerer Wertebereich.
Ein Nachteil ist der größere Speicherverbrauch, der aber nur bei sehr, sehr großen Arrays eine Rolle spielt.Würde das bei einem Programm mit 4-5 arrays der Größe 1000 etwas ausmachen?
DirkB schrieb:
Hast du denn mein abgewandeltes Beispiel mal ausgeführt?
Beim Preinkrement wird der Wert der Variablen vor dem Inkrement genommen.
Beim Postinkrement wird der Wert der Variablen nach dem Inkrement genommen.Sorry...Ich hatte gedacht, dass der Code dort mein Code wäre und du mich zitiert hast. Habe jetzt erst gesehen, dass das ein Beispiel war. Tut mir wie gesagt Leid, dir zwei mal Stress gemacht zu haben.
DirkB schrieb:
Das srand sollte nur einmal im ganzen Programm aufgerufen werden.
Du rufst es aber fünfmal auf.Ups, da ich am Ende die for-Schleife mit j hinzugefügt habe, ist das dort geblieben.
DirkB schrieb:
Du hast ein Array, das fünmal neu beschrieben wird.
Für das Array n bietet sich hier int an (oder sogar char), da du nur 2 (diskrete) Werte darin ablegen willst.
Und n[i] = rand() %2; macht das eleganter.Hmmm, ja das ist ja nicht so schlimm. Das war eee so ein Test für das Forum.
Nur geht es mir darum, dass das Ding jetzt mir etwas "falsches" ausgibt, bzw ich einen Fehler gemacht habe.Wenn ich den Code lese würde ich verstehen, dass mir dieses Programm 5 arrays ausgibt. Egal obs der selbe array ist oder nicht.
Bei mir kommt aber leider nur ein einziger array raus...Ich müsste ja eigentlich insgesamt 50 Zahlen bekommen (5 mal arrays Länge 10).
Doch mein Programm gibt mir nur 10 Zahlen.
Also funktioniert die erste for-Schleife mit j nicht???
-
Dein letztes Programm habe ich mir nicht so gründlich angesehen.
Der Index von Arrays fängt in C bei 0 an. Immer.
Mit float n[10]; definierst du ein Array mit 10 Elementen. Der Index geht von 0 bis 9
Das Element n[10] existiert nicht. Du greifst aber darauf zu und so kannst du dir andere Variablen überschreiben.Der richtig Schleifenkopf wäre for(i=0; i < 10; ++i){
i fängt bei 0 an und durch das < bleibt es bei 10 Durchläufen.
Warum nicht <= 9 ? Damit du auf einen Blick sehen kannst, das es 10 Durchläufe sind.Und gib beim
printf
noch ein paar Leerzeichen mit aus, damit du die einzelnen Zahlen auch erkennen kannst.Das mit 0 bis 1 bei
rand()
hast du jetzt wohl verstanden.
(RAND-MAX ist Systemabhängig. 32767 ist kein unüblicher Wert. D.h. es gibt dann aber auch nur 32768 verschiedene Werte, egal ob du sie auf 0 bis 1 umrechnest)wima_carsi38 schrieb:
Würde das bei einem Programm mit 4-5 arrays der Größe 1000 etwas ausmachen?
ein
double
belegt i.A 8 Byte. einefloat
4 Byte ²
Jetzt kannst du dir selber ausrechnen, wieviel Speicher das benötigt.
Wieviel Speicher hat dein Rechner? Welche Limits hat die Systemarchitektur³?
Machen die paar kByte bei 4 GByte Speicher etwas aus?²Das sind typische Werte. Die können auch anders sein.
³Unter DOS (im Real-Mode) konnten Arrays (ohne große Verrenkungen) nur 64 KByte groß sein. Auf Mikrocontrollern sieht es auch noch anders aus.