Twitter und Facebook-Anbindung
X
Tweet Follow @twitterapi
!!! Anbindung an twitter und facebook öffnen !!!

Wenn Ihnen mein Online-Buch gefällt,
dann bedanken Sie sich doch mit einer kleinen Spende...

11 Der Zufall

11 Der Zufall

Da der Zufall in der Informatik viel zu wichtig ist, um ihn dem Zufall zu überlassen, werde ich in diesem Kapitel kurz darüber sprechen, wie man Zufallszahlen generiert und was es dabei zu beachten gilt.

Zum Seitenanfang
Zum Inhaltsverzeichnis

11.2 Der zufällige Zufall

11.2 Der zufällige Zufall

Wie schaffen wSie es nun, immer eine andere Folge von zufälligen Zahlen zu erzeugen? Sicherlich wird man auf die Idee kommen, den Initialwert zufällig zu wählen, aber beißt sich da die Katze nicht in den Schwanz? Ohne weitere Überlegungen, würde sie das tun, aber es gibt Mittel und Wege einen zufälligen Initialwert zu bekommen, ohne "rand" aufrufen zu müssen. Der Trick ist, man benutzt das aktuelle Datum und die aktuelle Zeit. Vom Prinzip her könnte man zwar dann auch immer den gleichen Zufall bekommen, wenn man die Systemzeit zurück setzt, aber da die Uhrzeit auf die Millisekunde genau ist, ist es extrem schwer, es so zu organisieren, dass genau zu einem Zeitpunkt X der Computer die Funktion "srand" aufruft (um nicht zu sagen unmöglich).

Folgendes Beispiel wird wieder genau so sein wie eben, nur dass ich jetzt die Zeit für die Initialisierung des Zufalls verwenden werde.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
					
#include <stdlib.h>
#include <time.h>

// ...

srand((unsigned int)time(NULL));

// 5 Zufallszahlen erzeugen
for (int iCount = 0; iCount < 5; iCount++) {
	printf("%i ", rand());
} // end of for
					

In Zeile 6 sehen Sie jetzt, wie ich die aktuelle Zeit ermittle und das bringt mich auch gleich zu einem sehr wichtigen Hinweis. Bauten Sie die Funktion "srand" niemals in eine Schleife ein bzw. in eine rekursive Funktion. Jene werden meistens innerhalb einer Millisekunde ausgeführt, was zur Folge hat, dass man immer dieselbe Zeit ermittelt und somit immer den gleichen Startwert für den Zufall bekommt. Noch schlimmer wird es, wenn man in einer Schleife einmal "srand" und einmal "rand" aufruft. In diesem Fall bekommt man sogar immer die gleiche Zahl. Falls Sie sich also irgendwann mal wundern sollten, warum Ihtr zufällige Zahl gar nicht zufällig ist, dann liegt es an eben beschriebenem Szenario.

Zum Schluss möchte ich noch einen Lösungsansatz dafür aufzeigen, wie man zufällige Zahlen in einem bestimmten Intervall erzeugen kann, solange er unterhalb von 32767 liegt. Der Trick ist hier, dass man auf die zufällige Zahl den Modulo-Operator anwendet und anschließend das Ergebnis in den gewünschten Bereich verschiebt. Dies könnte z.B. so aussehen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
					
#include <stdlib.h>
#include <time.h>

// ...

srand((unsigned int)time(NULL));

int iVon	= 10;
int iBis	= 20;

// 5 Zufallszahlen erzeugen
for (int iCount = 0; iCount < 20; iCount++) {
	printf("%i ", rand() % (iBis-iVon+1) + iVon);
} // end of for
					

Ausgabe:

10 19 11 13 14 18 16 16 10 17 18 20 10 19 11 19 14 11 15 12
		

Wie mSie sehen, erzeuge ich mit obigen Code, 20 Zufallszahlen, welche im Bereich zwischen / einschließlich 10 und 20 liegen.

Eines sei an dieser Stelle noch erwähnt. Der intern verwendete Algorithmus zur Generierung der Zahlen ist zwar gut, aber nicht perfekt. Das heißt, manche Zahlen kommen öfters als andere vor. Die Gleichverteilung ist also nicht gegeben, sie kommt dem nur nahe. Wenn Sie es mir nicht glauben, können Sie ja mal ein Array von 1 bis 1000 bauen und eine Million mal eine zufällige Zahl erzeugen lassen und jene als Index für den Arrayzugriff benutzen, um den enthaltenen Wert zu inkrementieren. Wenn Sie sich jenes Array anschließend anschaut, werden Sie feststellen, dass die Werte teilweise stark variieren (was ja eigentlich nicht vorkommen dürfte) und dass sich bei mehrmaligem Ausführen ein Muster abzeichnet.

Zum Seitenanfang
Zum Inhaltsverzeichnis

11.1 Der statische Zufall

11.1 Der statische Zufall

Wie erstellt der Computer Zufallszahlen? Dafür gibt es einen Algorithmus, welcher mit einem Initialwert nacheinander komplexe Berechnungen durchführt und so immer eine vermeintlich zufällige Zahl liefert. Aber wie man aus dieser Erklärung vielleicht schon ableiten kann, wird mit einem gleichen Initialwert, immer der gleiche Zufall erzeugt. Schauen wir uns mal ein kleines Beispiel an, in welchem ich fünf zufällige Zahlen erzeuge und ausgebe.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
					
#include <stdlib.h>

// ...

srand(7);

// 5 Zufallszahlen erzeugen
for (int iCount = 0; iCount < 5; iCount++) {
	printf("%i ", rand());
} // end of for
					

Vorausgesetzt Sie haben nicht eine andere Version der "stdlib.h", sollten die Ausgaben immer wie folgt aussehen.

61 17422 15215 7040 15521
		

Falls bei Ihnen nicht diese Werte herauskommen, dann spielt das auch keine Rolle. Wichtig ist nur, dass, auch wenn es andere Werte sind, es immer die gleichen Werte sind.

Mit der Funktion "srand" können wir also einen Initialwert setzen, welcher Einfluss auf die zufälligen Zahlen hat. Mit der Funktion "rand" wird dann die eigentliche Zahl erzeugt, welche im Bereich zwischen / einschließlich 0 und 32767 liegt.

Zum Seitenanfang
Zum Inhaltsverzeichnis

11.3 Übungsaufgaben IX

11.3 Übungsaufgaben IX

  1. Schreiben Sie ein kleines Programm, welches ermittelt, wie gut der Zufall ist. Lassen Sie vom Benutzer den Wertebereich angeben (Maximalzahl) und eine Anzahl von Durchläufen. Anschließend soll eine Funktion "GenerateRandom" erstellt und darin ein Array angelegt werden, welches genau so groß ist wie der Wertebereich. Nachdem alle Werte mit 0 initialisiert wurden, soll eine Schleife mit der gewünschten Anzahl an Durchläufen, eine zufällige Zahl im Wertebereich erzeugen und an der entsprechenden Stelle im Array, den dortigen Wert um eins erhöhen. Abschließend soll die Funktion das Array zurück geben. Geben Sie in der "main" die Werte im Array aus und überprüfen Sie die Verteilung (theoretisch sollten überall ähnliche Werte sein, wenn der Zufall gut ist)
  2. Schreiben Sie ein kleines Programm zum generieren von Passwörtern. Dafür soll eine Funktion "GeneratePassword" erstellt werden, welche eine Länge übergeben bekommt und einen String zurück gibt. Das Passwort soll aus kleinen und große Buchstaben, sowie Ziffern bestehen, wobei sie mit der gleichen Wahrscheinlichkeit vorkommen sollen (1/3 klein, 1/3 groß, 1/3 Ziffer). In der "main" Funktion soll der Benutzer so lange Passwörter erzeugen können, bis er 0 als Länge angibt.
    TIPP: Es ist wahrscheinlich einfacher, wenn man erst entscheidet, was erzeugt werden soll und dann wiederum entscheidet was genau.
  3. Schreiben Sie ein Programm, welches das Spiel "Schere Stein Papier" realisiert. Dabei reicht es, wenn man nur gegen den Computer spielt und er mit gleicher Wahrscheinlichkeit, Schere, Stein oder Papier wählt. Versuchen Sie Ihr Programm so aufzubauen, dass die Eingabe und die Gewinnprüfung in extra Funktionen ausgelagert werden. In der "main" Funktion soll der Benutzer so lange das Spiel spielen können, bis er nicht mehr mag. Entscheiden Sie sich selbst für eine geeignete Abbruchbedingung. Während des Spiels, soll zudem mitgezählt werden, wie oft jeder gewonnen hat. Folgende Regeln sollen gelten: TIPP: Wenn Sie Enumerationen benutzen, wird ihr Quelltext Übersichtlicher.
Zum Seitenanfang
Zum Inhaltsverzeichnis

© Copyright by Thomas Weiß, 2009 - 2012