Schleifen (1)

Kurzwhile mit Kopfrechnen

Kopieren Sie das folgende Programm, starten Sie es mehrmals und lösen Sie die Aufgabe. Geben Sie auch falsche Lösungen ein


import java.util.*;
class Kopfrechnen {
  public static void main(String[] args) {
    Scanner Eingabe = new Scanner(System.in);
    int a, b, antwort;
    System.out.println("Kopfrechnen\n");
    a = (int)(Math.random()*21);
    b = (int)(Math.random()*21);
    int produkt = a*b;
    do {
      System.out.print("Wie viel ist "+a+" mal "+b+"? ");
      antwort = Eingabe.nextInt();
      if (produkt == antwort) {
        System.out.println("Prima. Du kannst es!");
      } else {
        System.out.println("Leider falsch!");
      }
    } while (produkt != antwort);
  }
}


Das Programm stellt eine Rechenaufgabe und fragt den Benutzer nach dem Ergebnis. Gibt er die richtige Zahl ein, so ist das Programm damit beendet, gibt er eine falsche Lösung ein, so wird die Frage wiederholt.

Der Kern dieses Programmes ist der Anweisungsblock  do { Anweisungen } while (Bedingung);

Kopfgesteuert, fußgesteuert oder was?

Weil die Bedingung erst am Schluss abgefragt wird, nennt man man nennt diese Konstruktion auch fußgesteuerte Schleife.
Das Gegenstück, die kopfgesteuerte Schleife kommt mit einem Wort weniger aus:  while (Bedingung) {Anweisungen};

Fußgesteuerte Schleifen werden mindestens einmal durchlaufen, bei kopfgesteuerten Schleifen kann es vorkommen, dass die Bedingung nicht erfüllt ist und die Schleife komplett übersprungen wird.

Löschen Sie das "do" und schieben Sie while (produkt != antwort); an dessen Platz vor die geschweifte Klammer. Das Programm sollte auch so funktionieren, aber Java protestiert trotzdem. Der Compiler merkt nämlich, dass die Variable antwort diesmal bei der ersten Abfrage noch keinen Wert enthält. Wenn Sie die Antwort mit int antwort=999 gleich bei der Deklaration mit einer Zahl vorbelegen, die nicht auftreten kann, dann funktioniert auch diese Variante.

Schleifen haben Tücken

Die Anweisungen in der geschweiften Klammer werden mehrmals ausgeführt: so oft bis die Bedingung hinter dem while erfüllt ist. Das macht natürlich nur Sinn, wenn im Anweisungsblock etwas passiert, das die Bedingung ändert. Ist der Benutzer zu dumm oder ist die Bedingung falsch formuliert, so läuft die Schleife endlos. Probieren Sie dieses Programm aus:


public class WhileTest {
  public static void main(String[] args) {
    int zähler = 0;
    double dividend = 1;
    System.out.println("Zahlen atomisieren\n");
    do {
      dividend = dividend/10;
      zähler++;
    } while (dividend != 0.0001);
    System.out.println("Ich habe die Eins "+zähler+" mal durch 10 dividiert");
  }
}


Na und? Das Programm teilt die Eins bei jedem Schleifendurchlauf durch 10 und zählt den Zähler jedes Mal um 1 hoch.
Das geht vier Mal so, dann sind nur noch 0,0001 übrig und die Bedingung nicht mehr erfüllt. Das Programm hält an.

Ändern Sie spaßeshalber mal die 0.0001 erst auf 0.00001, dann auf 0.000001.

Plötzlich läuft die Schleife endlos. Das liegt daran, dass der Computer nicht im Dezimalsystem rechnet. Er zeigt Zahlen zwar dezimal an, rechnet aber in Wirklichkeit im Dualsystem. Dort aber geht die Division durch 10 nicht genau auf. Es entstehen winzige Ungenauigkeiten, die den Computer daran hindern, festzustellen, dass das Ergebnis genau gleich 0,000001 ist.

Double-Zahlen sollte man also nie mit == oder != vergleichen, sondern stets mit <, <=, > oder >=.

Aufgaben:

  1. Schreiben Sie eine Klasse "Zahlenraten", die sich eine ganze Zahl ausdenkt, den Benutzer raten lässt und ihm dann mitteilt "zu groß", "zu klein" oder "stimmt". Zählen Sie die Anzahl der Versuche, die der Benutzer benötigt.

  1. Kopieren Sie noch einmal das ursprüngliche Kopfrechenprogramm. Bauen Sie außen um die do-while-Schleife herum eine weitere Schleife, die so lange neue Aufgaben erzeugt, bis der Benutzer zum Zeichen, dass er aufhören will, die "Lösung" 999 eingibt. Sie müssen auch die Bedingung der inneren while-Schleife anpassen.
  2. Programmieren Sie einen Lottozahlen-Ziehungsgenerator, der 6 Zahlen zwischen 1 und 49 zum Tippen vorschlägt.
    Im Gegensatz zum Ziehungsgerät des Fernsehens besteht bei Ihrem Generator die Gefahr, dass eine bereits gezogene Zahl nochmals vorgeschlagen wird. Verhindern Sie das mithilfe von while-Schleifen.
  3. Schreiben Sie ein Programm, das Zahlen abfragt und den laufenden Mittelwert aller eingegebenen Zahlen ausgibt.
  4. Heron von Alexandria (ca. 60 n. Chr.) überlieferte eine Verfahren zur Berechnung der Quadratwurzel einer gegebenen Zahl r:
    - Wähle einen anfänglichen Näherungswert n, es darf auch immer die 1 sein.
    - Bilde den Mittelwert aus n und r/n und verwende ihn als nächsten Näherungswert.
    - Brich das Verfahren nach 10 Durchläufen ab.
    - Gib den Näherungswert n aus.
  5. Für Profis: Ändern Sie die letzte Aufgabe so, dass die Näherung abbricht, wenn die gewünschte Genauigkeit erreicht ist
    (z.B., wenn sich n und r/n nur noch in der zehnten Nachkommastelle unterscheiden).
  6. Und noch eine Näherungsaufgabe: Wie erhalte ich zu einem gegebenen Winkel den Sinus? Voraussetzungen:
      a) Je kleiner ein Winkel, desto weniger unterscheidet sich der Sinus eines Winkels von der Länge des Kreisbogens.
      b) Kennt man den Sinus eines Winkels α, so erhält man sin 2α = 2·sin α ·Wurzel(1- (sin α)²).
    Folglich kann man den Sinus eines Winkels so berechnen:
      1. Halbiere den Winkel 20 mal.
      2. Berechne den Kreisbogen zu diesem Winkel für r=1 den Kreisbogen: b=2·r·π·α/180.
      3. Nimm diesen Wert als Sinus des Winkels und berechne 20 mal den Sinus des doppelten Winkels.
    Setzen Sie dieses Verfahren in ein Programm um.