Zufallszahlen und Feldvariablen

In diesem Kapitel sollen anhand eines Beispiels zwei wichtige Hilfsmittel beim Programmieren vorgestellt werden. Zum einen Zufallszahlen, zum anderen Feldvariablen.

== Zufallszahlen und Feldvariablen In diesem Kapitel sollen anhand eines Beispiels zwei wichtige Hilfsmittel beim Programmieren vorgestellt werden. Zum einen _Zufallszahlen_, zum anderen _Feldvariablen_.

Zufallszahlen mit Math.random()

=== Zufallszahlen mit Math.random()

Im folgenden soll ein Programm erstellt werden, das zufällig 100 Mal würfelt und am Ende ausgibt, wie oft jede Augenzahl vorkam.

Dazu benötigen wir Zufallszahlen, für dieses Beispiel zwischen 1 und 6 jeweils einschließlich. Eine solche Zufallszahl erhält man in Java mit Hilfe der Mathematik-Bibliothek, die die Funktion Math.random() zur Verfügung stellt.

Dieses liefert eine Zufallszahl zwischen 0 einschließlich und 1 ausschließlich zurück. Wir können das an einem kleinen Beispiel überprüfen:

Im folgenden soll ein Programm erstellt werden, das zufällig 100 Mal würfelt und am Ende ausgibt, wie oft jede Augenzahl vorkam. Dazu benötigen wir Zufallszahlen, für dieses Beispiel zwischen 1 und 6 jeweils einschließlich. Eine solche Zufallszahl erhält man in Java mit Hilfe der Mathematik-Bibliothek, die die Funktion `Math.random()` zur Verfügung stellt. Dieses liefert eine Zufallszahl zwischen 0 einschließlich und 1 ausschließlich zurück. Wir können das an einem kleinen Beispiel überprüfen:
for (int i=0;i<10;i++){
    double zz=Math.random();
    System.out.println(zz);
}
Java
[source,java,indent=0] ---- for (int i=0;i<10;i++){ double zz=Math.random(); System.out.println(zz); } ----

liefert die Ausgabe

liefert die Ausgabe
0.3238171227351645
0.9100171211441673
0.8780019536505819
0.5904566444523177
0.9567711972252289
0.024513772922905464
0.012812192915532705
0.3807497414944764
0.6158550994105622
0.6342264238947978
---- 0.3238171227351645 0.9100171211441673 0.8780019536505819 0.5904566444523177 0.9567711972252289 0.024513772922905464 0.012812192915532705 0.3807497414944764 0.6158550994105622 0.6342264238947978 ----

Startet man das Programm erneut, so erhält man 10 andere zufällige Zahlenwerte.

Startet man das Programm erneut, so erhält man 10 andere zufällige Zahlenwerte.

Anpassen des Bereichs von Math.random()

Um einen Würfel zu simulieren müssen wir den Zufallszahlenbereich von 0 bis 1 auf den Bereich von 1 bis 6 ausdehnen.

So ergibt

=== Anpassen des Bereichs von Math.random() Um einen Würfel zu simulieren müssen wir den Zufallszahlenbereich von 0 bis 1 auf den Bereich von 1 bis 6 ausdehnen. So ergibt
double zz=Math.random()*6;
Java
[source,java] ---- double zz=Math.random()*6; ----

Zufallszahlen von 0 einschließlich bis 6 ausschließlich.

Zählen wir noch 1 dazu, so erweitert sich der Bereich von 1 einschließlich bis 7 ausschließlich:

Zufallszahlen von 0 einschließlich bis 6 ausschließlich. Zählen wir noch 1 dazu, so erweitert sich der Bereich von 1 einschließlich bis 7 ausschließlich:
double zz=Math.random()*6+1;
Java
[source,java] ---- double zz=Math.random()*6+1; ----

liefert somit beispielsweise die folgenden Werte:

liefert somit beispielsweise die folgenden Werte:
4.703520713146365
5.3047722406694735
6.837098748234757
1.5115187837494568
1.40235950990028
5.825933724770314
3.292757861359862
5.018622861225861
5.765090973871817
5.560527244387773
---- 4.703520713146365 5.3047722406694735 6.837098748234757 1.5115187837494568 1.40235950990028 5.825933724770314 3.292757861359862 5.018622861225861 5.765090973871817 5.560527244387773 ----

Das sieht schon ganz gut aus. Nun schneiden wir noch die Nachkommastellen ab:

Das sieht schon ganz gut aus. Nun schneiden wir noch die Nachkommastellen ab:
int zz=(int)(Math.random()*6+1);
Java
[source,java] ---- int zz=(int)(Math.random()*6+1); ----

und erhalten dadurch die Zahlen 4, 5, 6, 1, 1, 5, 3, 5, 5, 5.

int z=(int) 3.7 speichert in der Ganzzahl-Variable z den Wert 3. Über das (int) vor der 3.7 teilt der Programmierer dem Compiler mit, dass man weiß, was man tut, nämlich einen double-Wert (3.7) in einen Ganzzahlenwert zu konvertieren. Dabei werden alle Nachkommastellen der Kommazahl abgeschnitten.

int z=3.7 würde zu einer Fehlermeldung führen, da in einer Ganzzahl-Variable keine Kommazahl gespeichert werden kann.

Den Vorgang des bewussten Umwandelns eines Datentyps in einen anderen bezeichnet man als Casting.

Das Casting funktioniert nicht zwischen beliebigen Datentypen!

int z=(int)"5";

also ein Casting von String nach int ist beispielsweise nicht möglich, wohl aber von double nach int oder von double nach byte (falls der Zahlenwert selbst nicht zu groß ist).

und erhalten dadurch die Zahlen 4, 5, 6, 1, 1, 5, 3, 5, 5, 5. [TIP] ==== `int z=(int) 3.7` speichert in der Ganzzahl-Variable `z` den Wert 3. Über das `(int)` vor der 3.7 teilt der Programmierer dem Compiler mit, dass man weiß, was man tut, nämlich einen double-Wert (3.7) in einen Ganzzahlenwert zu konvertieren. Dabei werden alle Nachkommastellen der Kommazahl abgeschnitten. `int z=3.7` würde zu einer Fehlermeldung führen, da in einer Ganzzahl-Variable keine Kommazahl gespeichert werden kann. Den Vorgang des bewussten Umwandelns eines Datentyps in einen anderen bezeichnet man als _Casting_. ==== [WARNING] ==== Das _Casting_ funktioniert nicht zwischen beliebigen Datentypen! ---- int z=(int)"5"; ---- also ein Casting von String nach int ist beispielsweise nicht möglich, wohl aber von double nach int oder von double nach byte (falls der Zahlenwert selbst nicht zu groß ist). ====

Häufigkeiten der Augenzahl zählen

Wie bereits erwähnt, soll nun ein Programm entstehen, das die absolute Häufigkeit von Augenzahlen bei 100-maligem Würfeln zählt.

Eine Möglichkeit wäre die folgende:

=== Häufigkeiten der Augenzahl zählen Wie bereits erwähnt, soll nun ein Programm entstehen, das die absolute Häufigkeit von Augenzahlen bei 100-maligem Würfeln zählt. Eine Möglichkeit wäre die folgende:
int s1=0,s2=0,s3=0,s4=0,s5=0,s6=0;
for (int i=0;i<100;i++){
    int zz=(int)(Math.random()*6+1);
    if (zz==1){
        s1++;
    } else if (zz==2){
        s2++;
    } else if (zz==3){
        s3++;
    } else if (zz==4){
        s4++;
    } else if (zz==5){
        s5++;
    } else if (zz==6){
        s6++;
    }
}

System.out.println(s1+"\n"+s2+"\n"+s3+"\n"+s4+"\n"+s5+"\n"+s6);
Java
[source,java,indent=0] ---- int s1=0,s2=0,s3=0,s4=0,s5=0,s6=0; for (int i=0;i<100;i++){ int zz=(int)(Math.random()*6+1); if (zz==1){ s1++; } else if (zz==2){ s2++; } else if (zz==3){ s3++; } else if (zz==4){ s4++; } else if (zz==5){ s5++; } else if (zz==6){ s6++; } } System.out.println(s1+"\n"+s2+"\n"+s3+"\n"+s4+"\n"+s5+"\n"+s6); ----

Als Ausgabe erhält man beispielsweise

Als Ausgabe erhält man beispielsweise
14
16
12
18
22
18
---- 14 16 12 18 22 18 ----

Hierbei gibt die 14 die Anzahl der gewürfelten Einser wieder, die 16 die Anzahl der Zweier, usw.

Das Programm funktioniert zwar, ist aber recht viel Schreibarbeit für im Prinzip immer wieder dasselbe.

Wäre es nicht schön, wenn man statt der ganzen if-Bedingung einfach etwas ähnliches wie

s_zz++

schreiben könnte, was bedeuten soll, dass je nach Inhalt der Variable zz die zugehörige Summe erhöht wird? Für zz=1 wird daraus

s_1++

für zz=2

s_2++

usw.

Tatsächlich ist so etwas möglich, nur mit einer etwas anderen Schreibweise.

Hierbei gibt die 14 die Anzahl der gewürfelten Einser wieder, die 16 die Anzahl der Zweier, usw. Das Programm funktioniert zwar, ist aber recht viel Schreibarbeit für im Prinzip immer wieder dasselbe. Wäre es nicht schön, wenn man statt der ganzen if-Bedingung einfach etwas ähnliches wie ---- s_zz++ ---- schreiben könnte, was bedeuten soll, dass je nach Inhalt der Variable zz die zugehörige Summe erhöht wird? Für `zz=1` wird daraus ---- s_1++ ---- für `zz=2` ---- s_2++ ---- usw. Tatsächlich ist so etwas möglich, nur mit einer etwas anderen Schreibweise.

Einführung von Feldvariablen

Eine Feldvariable kann man sich als durchnummerierte Variablen vorstellen.

Könnte man sich eine Variable als eine Kiste vorstellen, die bestimmte Typen von Daten beinhalten kann, so ist eine Feldvariable ein Schrank mit mehreren Schubladen, die durchnummeriert sind und jeweils den gleichen Datentyp speichern können, so wie beispielsweise ein Schrank mit mehreren durchnummerierten Schubladen in die nur int-Variablen hineinpassen.

Klicke mehrmals auf die Grafik, um den Unterschied zu verdeutlichen:

=== Einführung von Feldvariablen Eine Feldvariable kann man sich als durchnummerierte Variablen vorstellen. Könnte man sich eine Variable als eine Kiste vorstellen, die bestimmte Typen von Daten beinhalten kann, so ist eine Feldvariable ein Schrank mit mehreren Schubladen, die durchnummeriert sind und jeweils den gleichen Datentyp speichern können, so wie beispielsweise ein Schrank mit mehreren durchnummerierten Schubladen in die nur int-Variablen hineinpassen. Klicke mehrmals auf die Grafik, um den Unterschied zu verdeutlichen:

Um eine Feldvariable zu deklarieren (einzuführen), gibt man an, wie viele "Schubladen" es gibt und welche Datentypen in den Schubladen gespeichert werden können.

So erzeugt

int[] zahl=new int[6];
Java

eine neue Feldvariable mit dem Namen zahl, die Platz für sechs von 0 bis 5 durchnummerierte mögliche Einträge vom Typ int erhält.

Über eine Nummer in eckigen Klammern kann man auf die entsprechenden Einträge zugreifen:

zahl[3]=5;
System.out.println(zahl[3]);
Java

Die erste Zeile speichert die Zahl 5 in der "vierten Schublade". Der Inhalt dieser Schublade wird in der zweiten Zeile ausgegeben.

Die Nummerierung bei Feldvariablen beginnt immer bei der 0. Deshalb ist zahl[3] auch der Eintrag in der "vierten Schublade".

Um eine Feldvariable zu _deklarieren_ (einzuführen), gibt man an, wie viele "Schubladen" es gibt und welche Datentypen in den Schubladen gespeichert werden können. So erzeugt [source,java,indent=0] ---- int[] zahl=new int[6]; ---- eine neue Feldvariable mit dem Namen `zahl`, die Platz für sechs von 0 bis 5 durchnummerierte mögliche Einträge vom Typ `int` erhält. Über eine Nummer in eckigen Klammern kann man auf die entsprechenden Einträge zugreifen: [source, Java] ---- zahl[3]=5; System.out.println(zahl[3]); ---- Die erste Zeile speichert die Zahl 5 in der "vierten Schublade". Der Inhalt dieser Schublade wird in der zweiten Zeile ausgegeben. [WARNING] ==== Die Nummerierung bei Feldvariablen beginnt immer bei der 0. Deshalb ist `zahl[3]` auch der Eintrag in der "*vierten* Schublade". ====

Verbesserung unseres Programms mit Hilfe von Feldvariablen

Unser Programm mit dem Code

int s1=0,s2=0,s3=0,s4=0,s5=0,s6=0;
for (int i=0;i<100;i++){
    int zz=(int)(Math.random()*6+1);
    if (zz==1){
        s1++;
    } else if (zz==2){
        s2++;
    } else if (zz==3){
        s3++;
    } else if (zz==4){
        s4++;
    } else if (zz==5){
        s5++;
    } else if (zz==6){
        s6++;
    }
}

System.out.println(s1+"\n"+s2+"\n"+s3+"\n"+s4+"\n"+s5+"\n"+s6);
Java

kann durch die Verwendung von Feldvariablen umgeschrieben werden zu:

=== Verbesserung unseres Programms mit Hilfe von Feldvariablen Unser Programm mit dem Code [source,java,indent=0] ---- int s1=0,s2=0,s3=0,s4=0,s5=0,s6=0; for (int i=0;i<100;i++){ int zz=(int)(Math.random()*6+1); if (zz==1){ s1++; } else if (zz==2){ s2++; } else if (zz==3){ s3++; } else if (zz==4){ s4++; } else if (zz==5){ s5++; } else if (zz==6){ s6++; } } System.out.println(s1+"\n"+s2+"\n"+s3+"\n"+s4+"\n"+s5+"\n"+s6); ---- kann durch die Verwendung von Feldvariablen umgeschrieben werden zu:
int[] summe=new int[6]; (1)

for (int i=0;i<100;i++){
    int zz=(int)(Math.random()*6+1);
    summe[zz-1]++; (2)
}

for (int i=0;i<summe.length;i++){ (3)
    System.out.println(summe[i]); (4)
}
Java
[source,java,indent=0] ---- int[] summe=new int[6]; //<1> for (int i=0;i<100;i++){ int zz=(int)(Math.random()*6+1); summe[zz-1]++; //<2> } for (int i=0;i<summe.length;i++){ //<3> System.out.println(summe[i]); //<4> } ----
int[] summe=new int[6]; (1)

for (int i=0;i<100;i++){
    int zz=(int)(Math.random()*6+1);
    summe[zz-1]++; (2)
}

for (int i=0;i<summe.length;i++){ (3)
    System.out.println(summe[i]); (4)
}
1 Eine neue Feldvariable mit dem Namen summe und 6 möglichen int-Einträgen wird erzeugt.
2 Wird eine 1 gewürfelt, so wird der Inhalt von summe[0] um 1 erhöht, bei einer 2 der Inhalt von summe[1], usw.. Grund für das zz-1 ist die Tatsache, dass die Einträge einer Feldvariable ab 0 durchnummeriert sind.
3 summe.length liefert die Anzahl der "Schubladen" unserer Feldvariable summe zurück.
4 Hier wird der "i-te" Eintrag unserer Feldvariable ausgegeben.
[indent=0] ---- int[] summe=new int[6]; //<1> for (int i=0;i<100;i++){ int zz=(int)(Math.random()*6+1); summe[zz-1]++; //<2> } for (int i=0;i<summe.length;i++){ //<3> System.out.println(summe[i]); //<4> } ---- <1> Eine neue Feldvariable mit dem Namen `summe` und 6 möglichen int-Einträgen wird erzeugt. <2> Wird eine 1 gewürfelt, so wird der Inhalt von `summe[0]` um 1 erhöht, bei einer 2 der Inhalt von `summe[1]`, usw.. Grund für das `zz-1` ist die Tatsache, dass die Einträge einer Feldvariable ab 0 durchnummeriert sind. <3> `summe.length` liefert die Anzahl der "Schubladen" unserer Feldvariable `summe` zurück. <4> Hier wird der "i-te" Eintrag unserer Feldvariable ausgegeben.