Ein kleiner Programmierkurs - Teil 1.4: Schleifen - Immer wieder das gleiche

Eines der wichtigsten Konzepte in der Programmierung ist das Konzept der Schleifen.

Es kommt ganz häufig vor, dass man den Computer mehrmals hintereinander die gleiche oder zumindest eine sehr ähnliche Befehlsfolge ausführen lassen will. Da man nun nicht den gleichen Programmcode mehrmals hintereinander schreiben mag (insbesondere, wenn man erst während der Programmausführung weiß, wie oft man etwas machen möchte), verwendet man zur mehrfachen Wiederholung des Programmcodes eine Schleife.
Stellen Sie sich z.B. vor, Sie wollen einen Kollegen herausfinden lassen, wie groß das größte Kind in einer Klasse ist. Dann geben Sie ihm die Anweisungen:


Gehe in die Klasse
Miss das erste Kind und merke dir seine Größe.
Mit allen anderen Kindern mache folgendes:
    Miss das aktuelle Kind.
    Wenn seine Größe größer als die bisherige größte Größe ist, merke dir die aktuelle Größe.
Nenne mir dann die größte Größe.

Hier wissen Sie am Anfang nicht unbedingt, wie viele Kinder in der Klasse sind. Dies ist aber auch nicht nötig, da Sie gar nicht explizit sagen:


Miss Lukas
Miss Sophie
Miss Kevin
Miss Lisa
...

Erst, wenn Ihr Kollege in die Klasse geht, sieht er, wie viele Kinder er messen muss.

Ganz ähnliche Anweisungen können Sie auch Cinderella geben. Hier heißt der entsprechende Befehl forall.
forall erhält zwei Parameter. Der erste Parameter ist eine Liste all der Elemente, mit denen etwas gemacht werden soll (in obigem Beispiel eine Lise aller Kinder der Klasse). Der zweite Parameter ist eine Befehlsfolge, die jeweils mit dem aktuellen Element ausgeführt werden soll. Auf das aktuelle Element kann man dabei mit dem Hash-Symbol # zugreifen.

Als Beispiel wollen wir nun in unseren Funktionsgraphen die Stützbalken an den ganzzahligen Stützstellen x=0 bis x=10 einzeichnen.
Unsere Elemente, mit denen wir etwas tun wollen sind dabei die Zahlen 0,1,2,...,9,10, also die x-Werte. in Cinderella kann eine solche Liste mit 0..10 erzeugt werden, d.h. der Ausdruck 0..10 erzeugt eine Liste (0,1,2,3,4,5,6,7,8,9,10).
Für jeden Wert x dieser Liste soll nun zuerst die Stützstelle (x,f(x)) als kleiner Punkt gezeichnet werden. Dazu verwenden wir den Befehl draw.
Bekommt draw als Parameter die Koordinaten eines Punktes P=(xP,yP) in der Form [xP,yP], so zeichnet Cinderella einen kleinen grünen Punkt an diese Stelle. Es ist dabei zu beachten, dass dieser Punkt wirklich nur eine Zeichnung ist und so kein „echter“ Punkt als Objekt der geometrischen Konstruktion erzeugt wird. Diese Punkte können also nicht mit anderen Objekten in Cinderella interagieren.
Weiterhin wollen wir noch den Stützbalken von der x-Achse aus zeichnen. Das macht ebenfalls der Befehl draw, der jetzt jedoch als zweiten Parameter einen zweiten Punkt erhält: draw([xA,yA],[xB,yB]). In diese Variante wird die Strecke vom ersten Punkt A zum zweiten Punkt B gezeichnet.
Insgesamt ergänzen wir unser Programm also um folgende Zeilen:


forall(0..10,
    draw([#,f(#)]);
    draw([#,0],[#,f(#)]);
);

Da dies mit dem Hash-Symbol # schwer zu lesen ist, verwenden wir den forall-Befehl in einer zweiten Variante, die der Hash-Variablen einen anderen Namen gibt, hier z.B. i:


forall(0..10, i,
    draw([i,f(i)]);
    draw([i,0],[i,f(i)]);
);


Wir hätten statt i auch jeden anderen Namen vergeben können, z.B. auch x. Allerdings haben sich die Variablennamen i und j als sogenannte Laufvariablen bei Schleifen in der Informatik durchgesetzt, so wie in der MAthematik als Laufvariablen und Index z.B. in Summenformeln.
Insgesamt sieht unser Programm nun so aus:


f(x):=x/2+sin(x);
plot(f(x));
A.y=f(A.x); 
farbe(c):=[sin(c),sin(c+2*pi/3),sin(c-2*pi/3)];
A.color=farbe(A.x); 
forall(0..10, i,
    draw([i,f(i)]);
    draw([i,0],[i,f(i)]);
);

Bitte schalten Sie Java ein, um eine Cinderella-Konstruktion zu sehen.
Im nächsten Schritt wollen wir das Zeichnen der Stützstellen von der Position des Punktes A abhängig machen. Es sollen alle ganzzahligen Stützstellen von = bis zur x-Koordinate von A gezeichnet werden. Dazu ersetzen wir unsere Liste der x-Werte 0..10 durch 0..A.x. Interessanterweise funktioniert dies auch, wenn A.x nicht-ganzzahlig, also z.B. 9,37 ist. Es werden nur die ganzzahligen Anteile des Start- und Endwertes betrachtet, um die Liste zu erzeugen, d.h. Nachkommastellen werden abgeschnitten.


f(x):=x/2+sin(x);
plot(f(x));
A.y=f(A.x); 
farbe(c):=[sin(c),sin(c+2*pi/3),sin(c-2*pi/3)];
A.color=farbe(A.x); 
forall(0..A.x, i,
    draw([i,f(i)]);
    draw([i,0],[i,f(i)]);
);

Verschieben wir nun A, so werden die Stützstellen bis zu A gezeichnet.
Bitte schalten Sie Java ein, um eine Cinderella-Konstruktion zu sehen.
Allerdings verschwinden die Stützstellen, wenn A im negativen Bereich der x-Achse liegt. Dies liegt daran, dass zur Erzeugung einer Zahlenliste a..b mit dem ..-Operator a stets kleiner als b sein muss. Ansonsten erhalten wir eine leere Liste ohne Zahlen.
Um dies zu reparieren, müssen wir selbst entscheiden, ob A.x kleiner oder größer 0 ist. Wir verwenden wieder die if-Funktion und geben je nachdem die Liste 0..A.x oder A.x..0 zurück.


f(x):=x/2+sin(x);
plot(f(x));
A.y=f(A.x); 
farbe(c):=[sin(c),sin(c+2*pi/3),sin(c-2*pi/3)];
A.color=farbe(A.x); 
forall(if(A.x>=0,0..A.x,A.x..0), i,
    draw([i,f(i)]);
    draw([i,0],[i,f(i)]);
); 

Bitte schalten Sie Java ein, um eine Cinderella-Konstruktion zu sehen.
Zum Abschluss dieser Lektion möchte ich noch zwei andere Möglichkeiten vorstellen, wie das Problem mit den negativen x-Werten gelöst werden kann. Welche Lösung man bevorzugt ist geschmackssache, doch die letzte Variante wird im späteren Verlauf noch ein kleines wenig praktischer sein.
Wir wollen unabhängig vom Vorzeichen der x-Koordinate von A stets mit einer Liste von positiven Zahlen arbeiten. dazu benötigen wir zunächst den Absolutbetrag von A.x. Cinderella liefert uns dafür die Funktion abs. abs(x) liefert stets den Vorzeichenlosen Wert von x, also z.B. ist abs(2) gleich 2 aber abs(-3) ist 3.
Wir erzeugen unsere Liste also mit 0..abs(A.x). Damit ist die Liste niemals leer. Allerdings dürfen wir das Vorzeichen nicht ganz vergessen, denn wir wollen ja nach links zeichnen, wenn A.x kleiner als 0 ist. Deshalb führen wir zunächst eine Variable namens vorzeichen ein, die +1 sein soll, falls A.x>=0 ist, und -1, falls A.x<0. Mit diesem Vorzeichen müssen wir unsere Listenelemente später multiplizieren, um die korrekten x-Werte zu erhalten.


f(x):=x/2+sin(x);
plot(f(x));
A.y=f(A.x); 
farbe(c):=[sin(c),sin(c+2*pi/3),sin(c-2*pi/3)];
A.color=farbe(A.x); 
vorzeichen=if(A.x>=0,1,-1); 
forall(0..abs(A.x), i,
    draw([vorzeichen*i,f(vorzeichen*i)]);
    draw([vorzeichen*i,0],[vorzeichen*i,f(vorzeichen*i)]);
);

An der Programmausführung ändert sich damit jedoch gar nichts:



Bitte schalten Sie Java ein, um eine Cinderella-Konstruktion zu sehen.
Hier musste nun ständig die Laufvariable i (unser x-Wert) mit dem Vorzeichen multipliziert werden. Dies ist nicht nur schwer lesbar, bei aufwändigeren Programmen kann es die Ausführungsgeschwindigkeit verringern. deshalb wollen wir diese Multiplikation nur jeweils einmal ausführen und uns das vorzeichenbehaftete i in einer neuen Variablen vi merken.


f(x):=x/2+sin(x);
plot(f(x));
A.y=f(A.x); 
farbe(c):=[sin(c),sin(c+2*pi/3),sin(c-2*pi/3)];
A.color=farbe(A.x); 
vorzeichen=if(A.x>=0,1,-1); 
forall(0..abs(A.x), i,
    vi=vorzeichen*i;
    draw([vi,f(vi)]);
    draw([vi,0],[vi,f(vi)]);
);

Gegenüber unserer ersten Version hat sich nicht so viel geändert, außer dass wir uns nicht mehr so viel Geanken machen müssen, ob wir links oder rechts von der Null sind. Wir merken uns das nur einmal im Vorzeichen, mit dem wir unsere Listenelement jeweils einmal multiplizieren. Dies macht uns im nächsten Schritt das Leben leichter, wenn wir anfangen wollen, die Funktion graphisch zu integrieren.
Bitte schalten Sie Java ein, um eine Cinderella-Konstruktion zu sehen.

Im nächsten Teil geht es etwas mathematischer weiter: wir wollen die Funktion integrieren, indem wir den Flächeninhalt unter der Kurve näherungsweise mittels Trapezflächen berechnen.