3.2.3 Beispiele ohne Turtle
 


Stanislav Ulam

Zur nachfolgenden Demonstration eines weiteren Beispiels für Verzweigung wollen keine Turlte benutzen. Wir lernen quasi nebenbei, wie man einfache Programme, ohne jegliche Vorgabe schreiben kann. Sie sind von der Oberfläche wenig ansprechend, das sie zur Ein- und Ausgabe das Ausgabefenster von Windows benutzt, also keine eigentliche Windowsoberfläche besitzt. Diese Programme sind ideal für das Testen von Algorithmen geeignet. Hier begegnen wir ihnen zum ersten Mal.
 
 Ulam-'Spiel' Das Ulam-'Spiel' hat folgende Spielregeln:

Wählen Sie eine beliebige positive Zahl, die größer als 1 ist. und führen Sie den folgenden Algorithmus durch:

Wiederhole
     wenn Zahl gerade dann halbiere sie
     sonst nimm sie mal 3 und füge 1 hinzu

Nehmen wir als Startwert 3, so ergibt sich folgende Folge:

3 - 10 - 5 - 16 - 8 - 4 - 2 - 1 - 4 - 2 - 1 - 4 - 2 - 1....

Eigentlich können wir bei 1 aufhören, da sich danach die Zahlen 4 - 2 - 1 immer wieder wiederholen.

Für die Startzahl 23 erhalten wir die Zahlenfolge:

23 - 70 - 35 - 106 - 53 - 160 - 80 - 40 - 20 - 10 - 5 - 16 - 8 - 4 - 2 - 1

Auch hier hören wir wieder bei 1 auf.
 
Link:
Stanislaw Ulam

Das eigenartige an diesen nach unserer Spielregel erzeugten Zahlenfolge ist, dass sie Zahlen liefert, die mal größer mal kleiner ohne, ohne dass eine Regel für das Auf und Ab gefunden werden könnte. Auch dass alle bekannten Folgen irgendwann auf die 1 stoßen wirkt überraschend. Für die Vermutungen, dieser Zahlenfolgen betreffend hat man bis heute noch keinen mathematischen Beweis gefunden.  Benannt wird diese Folge nach ihrem Erfinder, dem Mathematiker Ulam. Was ist nahe liegender, als die Zahlen einer Ulamfolge durch ein Programm errechnen zu lassen.

Der eigentliche Algorithmus zur Berechnung der Folgengleider ist nicht sehr schwer:

if (i % 2 ==0){
  i = i/2;
}
else{
  i = i*3+1;
}
  Wir nehmen einmal an, dass die Ulam-Folge irgendwann die 1 trifft, dann liegt es nahe die Berechnungen in einer while-Schleife zu organisieren und sie beim Erreichen der 1 zu beenden.
 
while (i != 1){
  if (i % 2 ==0){
    i = i/2;
  }
  else{
    i = i*3+1;
  }
}

Fehlt noch die Einbindung in ein lauffähiges Programm. Wir verwenden dazu die folgende Vorlage:
 

public class Ulam {

  public static void main (String[] args) {
     //hier kommt der 'eiogentliche' Programmkode hin
  }
}


 
public class Ulam {

  public static void main (String[] args) {
    int i = 23;
    while (i != 1){
      if (i % 2 ==0){
        i = i/2;
      }
      else{
        i = i*3+1;
      }
      System.out.println(i);
    }
  }
}
In der ersten gelb markierten Zeile

int i = 23;

die wir auch ausführlicher in zwei Zeilen:

int i;
i = 23;

hätten schreiben können, wird eine Variable vom Typ int deklariert und mit dem Wert 23 initialisiert. Die zweite markierte Zeile

System.out.println(i);

veranlasst, dass der Wert von i, der bei jedem Schleifendurchgang einmal berechnet wird auch ausgegeben wird. So können wir das Verhalten der Folgenglieder beobachten. In unserem Fall ergeben sich als Ausgabewerte:

70 - 35 - 106 - 53 - 160 - 80 - 40 - 20 -10 - 5 - 16 - 8 - 4 - 2 - 1
 

Es ist lästig, jedes Mal, wenn man einen anderen Startwert wählen möchte, dem Quelltext zu verändern. Eine Eingabe über Tastatur (Konsole) bei laufenden Programm wäre wesentlich bequemer.
 
Download: Ulam.java
import info1.*;
public class Ulam {

  public static void main (String[] args) {
    System.out.print("Ganze Zahl > 1: ");
    int i = Console.in.readInt();        
    while (i != 1){
      if (i % 2 ==0){
        i = i/2;
      }
      else{
        i = i*3+1;
      }
      System.out.println(i);
    }
  }
}
Mit Console.in.readInt() liest das Programm von der Tastatur eine ganze Zahl, die dan nin der Variablen i gespeichert wird. Diese Anweisung ist allerdings nicht in der Standardbibliothek von Java angelegt. Sie muss deshalb importiert werden. Deshalb haben wir in der ersten Zeile den den import info1.*; zu ergänzen. (vgl. dazu A3 Das info1-Paket)
 

Ein weiteres Beispiel:
 

Math.abs() In der Klasse Math gibt es eine Klassenmethode abs(), mit Hilfe derer man den Betrag einer Zahl bestimmen kann. Können wir selbst ein Programm schreiben, das den Betrag einer eingegebenen Zahl berechnet?
 
Struktogramm zu abs Der Algorithmus der den Betrag einer ganzen Zahl berechnet ist so definiert:

Diese Definition lässt sich leicht in ein Struktogramm mit einer einfachen Verzweigung übersetzen:

Schließlich übersetzen wir die dargestellte Struktur in Javacode:

if (x >= 0){
  System.out.println("abs("+x+") = "+x);
}
else {
  System.out.println("abs("+x+") = "+(-x));
}

Die Ausgabe in den beiden Zweigen ist einfach zu lesen. Wir erinnern uns, System.out.println(...) gibt das aus, was in den Klammern steht . Das hier rot innerhalb der "-Zeichen geschriebene Text wird so ausgegeben, wie er geschrieben ist. Die x bzw. -x sind Variabel mit einem bestimmten Wert. Sie sind nicht in Anführungsstrichen geschrieben, es wird also nicht x bzw. -x  sondern die Werte von x und -x auf den Bildschirm ausgegeben. Die Teilausgaben werden mit dem +-Zeichen zusammengehängt, oder wie wir im Fachjargon gerne sagen, konkateniert.
 

Download:
DemoAbs.java
Das ganze Programm:
import info1.*;
public class DemoAbs {

  public static void main (String[] args) {
    System.out.print("Geben Sie eine ganze Zahl ein: ");
    int x = Console.in.readInt();
    if (x >= 0){
      System.out.println("abs("+x+") = "+x);
    }
    else {
      System.out.println("abs("+x+") = "+(-x));
    }
  }
}
Math.max(a,b) Auch das zweite Beispiel, ist einer Klassenmethode der Klasse Math nachempfunden. Es soll ein Programm geschrieben werden, das das Maximum zweier eingegebener Zahlen bestimmt und in einer Variable max ablegt. Das Struktogramm hilft:

 

Downlaod:
DemoMax2.java
import info1.*;
public class DemoMax2 {

  public static void main (String[] args) {
    System.out.print("Geben a ein: ");
    int a = Console.in.readInt();
    System.out.print("Geben b ein: ");
    int b = Console.in.readInt();
    int max;
    if (a>=b){
      max = a;
    }
    else{
      max = b;
    }
    System.out.println("Max("+a+","+b+") = "+max);
  }
}
In der Struktur ist diese Programm dem vorausgehenden sehr ähnlich. Es hat eine kleine Variante. In den Verzweigungen wir nichts mehr ausgegeben, sondern der Wert von max bestimmt. Die Ausgabe des Wertes von max erfolgt jetzt nach der Verzweigung, wenn also die beiden alternativen Programmstränge wieder zusammengelaufen sind.

Wir betrachten nun eine kleine Variante. Es soll die sie größte von drei eingegebenen Zahlen bestimmt werden. Das Struktogramm sieht jetzt so aus, wie es rechts dargestellt ist.

Nach der Eingabe von drei Zahlen a, b und c, hier im Struktogramm nicht dargestellt, wird zunächst die größere der ersten beiden bestimmt und in max gespeichert. Danach wird geprüft ob die dritte Zahl vielleicht noch größer ist als max und gegebenenfalls wird max mit dem Wert von c überschritten. Ist c dagegen kleiner als das zuerst berechnete Maximum, muss nichts mehr berechnet werden. Der Zweig bleibt leer.
 

Download:
DemoMax3.java
import info1.*;
public class DemoMax3 {

  public static void main (String[] args) {
     System.out.print("Geben a ein: ");
     int a = Console.in.readInt();
     System.out.print("Geben b ein: ");
     int b = Console.in.readInt();
     System.out.print("Geben c ein: ");
     int c = Console.in.readInt();
     int max;
     if (a>=b){
       max = a;
     }
     else{
       max = b;
     }
     if (c>max){
       max = c;
     }
     System.out.println("Max("+a+","+b+","+c+") = "+max);
  }
}
zu 3.2.4 Übungen
zur Startseite www.pohlig.de  (C) MPohlig 2006