Möchte man eine Anweisung (einen Block) wiederholt ausführen, so gibt es dafür in Pascal drei verschiedene zusammengesetzte Anweisungen, die jeweils unterschiedliche Kontrollstrukturen bilden. Die Unterschiede bestehen in der Form, in der die Bedingung formuliert wird, unter der die Anweisung wiederholt wird. Zunächst wird die am häufigsten benutzte Wiederholungsanweisung, die While-Anweisung, beschrieben.
Bild 16: Struktur der While-Anweisung
PROGRAM WHILEDEMO (INPUT,OUTPUT); VAR VON,BIS,X: INTEGER; BEGIN WRITE('VON BIS :'); READLN(VON,BIS); X:= VON; WHILE X<=BIS DO BEGIN WRITE(X); X:= X+1 END; END.
Bild 17: Eine einfache While-Schleife
Eine While-Anweisung wird folgendermaßen ausgeführt:
In Bild 17 wird also der Wert der Variablen X solange mit WRITE ausgegeben und um 1 erhöht, bis X größer als die Variable BIS wird. Beispiele für die Ausgaben des Programmes zeigen eine wichtige Eigenschaft der While-Anweisung:
VON BIS: 1 5 1 2 3 4 5 VON BIS: 1 2 1 2 VON BIS: 1 1 1 VON BIS: 1 0Ist also wie bei der letzten Eingabe die Bedingung bereits beim Eintritt in die Schleife nicht erfüllt, wird die Anweisung überhaupt nicht ausgeführt. In diesem Beispiel wurde wieder eine mit BEGIN und END geschachtelte Anweisungsfolge verwendet, um mehr als eine Anweisung nach dem Wortsymbol DO zu wiederholen.
Das nächste Programmbeispiel in Bild 18 berechnet die Anzahl der Stellen einer ganzen Zahl. Die Idee besteht darin, zu zählen, wie oft man die Zahl X nach rechts schieben kann, bis alle Ziffern hinter dem Komma stehen:
PROGRAM STELLEN (INPUT,OUTPUT); VAR X,N : INTEGER; BEGIN READLN(X); N:= 0; (* N zählt die Divisionen *) WHILE X<>0 DO BEGIN X:= X DIV 10; N:= N+1 END; WRITELN('Anzahl der Stellen:', N); END.
Bild 18: Dezimalstellen zählen
Wichtig ist dabei die Tatsache, daß die Prüfung des Ausdruckes (X<>0) vor der Ausführung der Anweisungen (X:= X DIV 10; N:= N+1) erfolgt. Deshalb wird für die Eingabe der Zahl X=0 die Schleife überhaupt nicht durchlaufen, weshalb das Programm für diese Eingabe das Ergebnis N=0 liefert. Anzumerken ist noch, daß das Programm auch für negative Zahlen korrekt arbeitet.
Nach der ausführlichen Diskussion im letzten Abschnitt ist Ihnen sicher auch klar, warum im Programm STELLEN nach dem Wortsymbol DO eine Anweisungsfolge (BEGIN ... END) steht. Ist dies nicht der Fall, sollten Sie das Programm probeweise ohne die Klammerung mit BEGIN und END übersetzen und testen. Wenn Sie anschließend die beiden letzten Kapitel noch einmal lesen, werden Sie die Bedeutung der Anweisungsfolge zur Bildung von Anweisungsblöcken erkennen.
PROGRAM NETZ (INPUT,OUTPUT,GRAPHIC); CONST N1 = 8; N2 = 8; VAR P1,P2: INTEGER; BEGIN GRAPHIC(1,1); P1:= 1; WHILE P1<=N1 DO BEGIN P2:= 1; WHILE P2<=N2 DO BEGIN (* Zeichne eine Linie: *) DRAW(1, (* Farbe *) P1*40, P1*0, (* Startpunkt *) P2*0, P2*20); (* Endpunkt *) P2:= P2+1; END; P1:= P1+1 END; REPEAT UNTIL KEYPRESSED; (* Warte auf Tastatureingabe *) GRAPHIC(0); END.
Bild 19: Geschachtelte While-Anweisungen
In Bild 19 werden zwei geschachtelte WHILE-Anweisungen verwendet, um ein Netz im Grafikmodus zu zeichnen. In Pascal 2.0 muß bei der Verwendung des Grafikmodus der Name GRAPHIC im Programmkopf aufgeführt werden. Nachdem mit der Anweisung GRAPHIC der Grafikbildschirm eingeschaltet wurde, werden N1 Punkte mit N2 Punkten durch je eine Linie verbunden. Dabei zählt die Variable P1 in der äußeren While-Anweisung von 1 bis N1, während die Variable P2 in der inneren While-Anweisung von 1 bis N2 zählt.
Die Prozedur DRAW (s.a. Kapitel 4.4.4.9) verbindet nun jeweils zwei Punkte (P1 und P2) in der Zeichenfarbe (1). Durch die Wahl der Faktoren (20, 0 ,25, 10) werden zwei Geraden auf dem Bildschirm definiert, auf denen jeweils die Start- und Endpunkte der Linien in gleichem Abstand liegen. Im Programm werden die Punkte nun nach folgendem Schema verbunden:
P1 auf
Gerade 1 |
mit P2 auf
Gerade 2 |
1
|
1, 2, 3, 4, 5, 6, 7, 8
|
2
|
1, 2, 3, 4, 5, 6, 7, 8
|
...
|
...
|
8
|
1, 2, 3, 4, 5, 6, 7, 8
|
Bild 20: Lage der Linienendpunkte
Insgesamt werden also N1 * N2 = 64 Linien gezeichnet. Durch eine Änderung der Faktoren bei der DRAW-Prozedur und die Variation der Punkteanzahlen (N1 und N2) können Sie verschiedene Effekte erzielen. Probieren Sie doch zum Beispiel
N1 = 10; N2 = 10 DRAW(1, P1 * 32, 100, 160 , P2 *20)
While-Anweisungen nennt man auch pre check loops oder abweisende Schleifen. Durch die Eigenschaft einer While-Anweisung, die Schleife auch keinmal auszuführen, spart man oft notwendige Sonderbehandlungen. Das letze Beispielprogramm dieses Abschnittes berechnet für zwei natürliche Zahlen N und K den Wert E = N hoch K.
PROGRAM HOCH (INPUT, OUTPUT); VAR E,N,I,K : INTEGER; BEGIN READLN(N,K); E:= 1; I:=K; WHILE I>0 DO BEGIN E:= E*N; I:= I-1 END; WRITELN(N, '^', K, '=', E); END.
Dieses Programm berücksichtigt auch die Sonderfälle N=0 und K=0 korrekt. Es gilt nämlich:
N hoch 0 = 1 für alle N 0 hoch K = 0 für alle K<>0
Auch für die Repeat-Anweisung, die erst im nächsten Abschnitt vorgestellt wird, gelten die folgenden Regeln, die man bei der Programmierung von Wiederholungsanweisungen beachten sollte:
WHILE I<>0 DO K:= K+1
E:=1; I:= K; WHILE I>0 DO (* E = X hoch (K-I) *) BEGIN E:= E*N; I:= I-1 END
Am Ende der Schleife ist also I=0, und damit besitzt E den gewünschten Wert.
Seltener als die While-Anweisung wird die Repeat-Anweisung benutzt. Sie hat die in Bild 21 angegebene Struktur:
Bild 21: Repeat-Anweisung
Der wesentliche Unterschied zur While-Anweisung ist die Tatsache, daß die Anweisungsfolge mindestens einmal ausgeführt wird, da eine Repeat-Anweisung folgendermaßen ausgeführt wird:
Im Gegensatz zur While-Anweisung kann damit der boolesche Ausdruck Variablen enthalten, die erst innerhalb der Anweisungsfolge berechnet werden.
PROGRAM SIMPLEREPEAT(INPUT,OUTPUT); VAR CH: CHAR; BEGIN REPEAT WRITE('Allles klar? (J,N) '); READLN(CH) UNTIL (CH='J') OR (CH='N'); IF CH ='J' THEN WRITELN('Na prima!') ELSE WRITELN('Ist doch gar nicht schwer!'); END.
Eine beliebte Anwendung der Repeat-Anweisung besteht nur aus einer Abbruchbedingung ohne Anweisungen zwischen REPEAT und UNTIL:
REPEAT UNTIL KEYPRESSED;
Die in Pascal 2.0 vordefinierte Funktion KEYPRESSED liefert den Wert TRUE, falls der Benutzer eine Taste betätigt hat. Somit wird die (leere) Repeat-Schleife bis zur Betätigung einer Taste durchlaufen. In Bild 19 wurde diese Schleife zum Beispiel verwendet, um vor dem Löschen des Grafikbildschirms auf einen Tastendruck des Benutzers zu warten.
Im nächsten Beispiel wird die Repeat-Anweisung zum Zeichnen einer Funktion benutzt.
PROGRAM PLOT (INPUT,OUTPUT,GRAPHIC); CONST BILDSCHIRMBREITE = 319; PIXELSCHRITT = 3; VAR XPIXEL, YPIXEL : INTEGER; X, VON, BIS,Y : REAL; FAKTOR : REAL; BEGIN WRITELN('Intervallgrenzen'); WRITE('von :'); READLN(VON); WRITE('bis :'); READLN(BIS); FAKTOR:= (BIS-VON) / BILDSCHIRMBREITE; GRAPHIC(1,1); COLOR(1,1); (* schwarze Farbe *) XPIXEL:= 0; REPEAT (* Berechne X-Wert aus XPIXEL: *) X:= VON + XPIXEL * FAKTOR; Y:= SIN(X) + 2 * COS(3*X); YPIXEL:= ROUND( Y*40) + 100; (* Y Werte skalieren *) IF XPIXEL = 0 THEN (* 1. Punkt *) LOCATE(XPIXEL,YPIXEL) ELSE DRAW(1,,XPIXEL,YPIXEL); (* ziehe Linie *) XPIXEL:= XPIXEL + PIXELSCHRITT; UNTIL XPIXEL>BILDSCHIRMBREITE; REPEAT UNTIL KEYPRESSED; GRAPHIC(0); END.
Das Programm läßt sich dreiteilen: Zunächst werden die Grenzen des darzustellenden Koordinatenbereichs der Funktion eingegeben. In der nachfolgenden Repeat-Schleife wird die Funktion von links nach rechts in voller Bildschirmbreite ausgegeben. Abschließend wird vor dem Löschen des Bildschirms auf eine Tastatureingabe des Benutzers gewartet. Wählen Sie z.B. folgende Eingabewerte
VON : -10 BIS : 10
wird die Funktion
Y = SIN(X) + 2 * COS(3*X)
im Intervall [-10, 10] dargestellt. Innerhalb der Repeat-Schleife wird mit den Prozeduren LOCATE und DRAW (s. 4.4.4.9) eine zusammenhängende Linie gezogen. Dabei wird in jedem Durchlauf der Schleife ein Bildschirmkoordinatenpaar XPIXEL / YPIXEL berechnet. Mit der bedingten Anweisung IF XPIXEL=0 wird folgende Zeichenstrategie gewählt:
Der 1. Bildschirmpunkt wird mit LOCATE als Anfangspunkt eines Linienzuges definiert. In jedem folgenden Durchlauf wird der neu berechnete Punkt mit dem zuletzt gemalten Punkt verbunden.
Während XPIXEL mit der Schrittweite PIXELSCHRITT von 0 bis BILDSCHIRMBREITE hochgezählt wird, muß YPIXEL gemäß der Funktion in jedem Durchlauf neu berechnet werden. Mit der Zuweisung
X:= VON + XPIXEL * FAKTOR
wird der Bereich der ganzzahligen Bildschirmkoordinaten von 0 bis BILDSCHIRMBREITE auf den Bereich der X-Koordinaten der Funktion (z.B. [-10,10]) abgebildet. Dabei nimmt der Compiler automatisch eine Umwandlung vom Typ INTEGER zum Typ REAL vor. Nachdem so die Koordinate X berechnet wurde, kann diese in die Funktion eingesetzt werden, um die Y-Koordinate Y zu berechnen. Schließlich muß diese reelle Zahl Y wieder auf den Bereich der darstellbaren ganzzahligen Y-Bildschirmkoordinaten (von 0 bis 199) umgeformt werden.
Dies geschieht mit der Rundungsfunktion ROUND:
YPIXEL:= ROUND (40*Y) + 100
Zur Abwechselung können Sie auch die folgende Funktion im Bereich von -20 bis 20 darstellen:
Y:= 2 * SIN(X) / X
In BASIC bietet die For-Anweisung die beste Möglichkeit zur Strukturierung von Wiederholungen. In Pascal wird die For-Anweisung nur dann verwendet, wenn die Anzahl der Wiederholungen bereits vor dem Eintritt in die Schleife bekannt ist. Die Struktur der Anweisung ist wieder in einem Bild dargestellt:
Bild 22: Struktur der For-Anweisung
Die Ausführung erfolgt nach dem folgenden Schema. Es sichert, daß der Endwert der Schleife nicht in der Schleife verändert werden kann. Außerdem kann die For-Schleife wie die While-Schleife auch keinmal durchlaufen werden, falls nämlich der Wert von Ausdruck 1 bereits größer als der Wert von Ausdruck 2 ist:
Das folgende kleine Programm bestimmt die Summe der Kehrwerte der Zahlen von 1 bis 100:
PROGRAM FORLOOP(OUTPUT); VAR S: REAL; I: INTEGER; BEGIN S:= 0.0; FOR I:= 1 TO 100 DO S:= S + 1 / I; WRITELN(S); END.
Als Typ der Laufvariablen sind alle skalaren Typen (z.B. INTEGER, CHAR, BOOLEAN, nicht aber REAL) zulässig. Dementsprechend wird in Schritt (4) allgemein der Nachfolger im Wertebereich bestimmt:
PROGRAM FORCHAR (OUTPUT); VAR CH: CHAR; BEGIN FOR CH:= ' ' TO 'Z' DO WRITELN('Der Code von ', CH,' ist', ORD(CH):4); END.
Die einzige Möglichkeit zur Änderung der Schrittweite einer FOR- Anweisung besteht darin, abwärts zu zählen:
FOR Variable:= Ausdruck 1 DOWNTO Ausdruck 2 DO Anweisung
Die Variable durchläuft also ihren Wertebereich zwischen Ausdruck 1 und Ausdruck 2 rückwärts:
PROGRAM BACKANDFOR(OUTPUT); VAR CH: CHAR; BEGIN FOR CH:= 'Z' TO 'A' DO WRITE(CH); WRITELN('Schleife 1 beendet'); FOR CH:= 'Z' DOWNTO 'A' DO WRITE(CH); WRITELN; WRITELN('Schleife 2 beendet') END.
Die erste Schleife wird keinmal durchlaufen, da 'Z' größer als 'A' ist, wohingegen in der zweiten Schleife die Buchstaben von 'Z' bis 'A' rückwärts gedruckt werden.
PROGRAM SEHTRA (INPUT,OUTPUT); (* Berechnung eines bestimmten Integrals nach der *) (* summierten Sehnentrapezformel: *) (* (Es gibt wesentlich bessere Methoden!) *) VAR SIGMA : REAL; VON, BIS ,X ,F ,H : REAL; I,N : INTEGER; BEGIN WRITE('Integrationsgrenzen:'); READLN(VON, BIS); WRITE('Stützstellen:'); READLN(N); H:= (BIS-VON) / N; SIGMA:= 0; FOR I:= 0 TO N DO BEGIN X:= VON + I * H; F:= SIN(X); IF (I=0) OR (I=N) THEN SIGMA:= SIGMA + F / 2 ELSE SIGMA:= SIGMA + F END; WRITELN('Näherung:', SIGMA * H); END.
Bild 23: Numerische Integration
In diesem Beispielprogramm wird das bestimmte Integral der Funktion F = SIN(X) in einem frei wählbaren Intervall mit der einfachen Sehnentrapezregel (s. Mathematik-Schulbücher) angenähert. Dazu berechnet man (N+1) Funktionswerte an äquidistanten Stützstellen, die jeweils den Abstand H voneinander besitzen. Bildet man nun die Summe über diese Funktionswerte, wobei die Werte am Intervallrand (I=0) oder (I=N) nur halb gewichtet werden, so ist das Produkt SIGMA * H eine Näherung für das Integral der Funktion zwischen VON und BIS.
Die Genauigkeit der Näherung hängt unter anderem von der Anzahl der Stützstellen ab. Solange nicht Rundungsfehler das Ergebnis beeinflussen, steigt die Genauigkeit mit dem Quadrat der Anzahl der Stützstellen.
Da als Laufvariable keine reellen Zahlen zulässig sind, ist folgende Schleife nicht in Pascal möglich:
FOR X:= VON TO BIS STEP H DO ... FALSCH !
Solche Schleifen bieten nämlich eine ideale Grundlage für undurchsichtige Fehler, falls bei der sukzessiven Addition der Schrittweite H Rundungsfehler auftreten. Als abschreckendes Beispiel sollten Sie in BASIC folgendes Programm probieren:
FOR I=-1 TO 1 STEP 0.1: PRINT I: NEXT
Durch Rundungsfehler werden nur 20 (statt 21) Zahlen gedruckt! Die in Programm 23 gewählte Methode benötigt zwar bei jedem Schleifendurchlauf eine zusätzliche Multiplikation, jedoch können sich dort Rundungsfehler nicht kumulieren.
Die Ausgabe einer Multiplikationstabelle ist ein anschauliches Beispiel für geschachtelte For-Schleifen:
PROGRAM MULTIPLIKATION (OUTPUT); CONST N=13; VAR I,J: INTEGER; BEGIN FOR I:= 1 TO N DO BEGIN FOR J:= 1 TO N DO WRITE(I * J : 3); WRITELN; END; END.
Dabei durchläuft die Variable J in der inneren Schleife die Werte 1 bis 13, während die Variable I in der äußeren Schleife die momentan gedruckte Zeile zählt. In jeder Zeile werden die Produkte I*J gedruckt.
In diesem Abschnitt werden enzyklopädisch alle Regeln zusammengestellt, die die Sprunganweisung betreffen. Deshalb werden einige Begriffe auftreten, die erst in späteren Abschnitten erklärt werden.
Sprunganweisungen sollten nur zur Behandlung selten auftretender Ausnahmefälle in einem Programm benutzt werden. Außerdem ist es sinnvoll, bei einer Sprunganweisung Kommentare einzufügen, die erläutern, wohin und warum gesprungen wird.
Eine Sprunganweisung hat die folgende Syntax:
GOTO Label
Die Programmausführung wird beim Erreichen der Sprunganweisung an der Anweisung fortgesetzt, die durch das Label markiert wird. Ein Label ist eine positive ganze Zahl. Jede Anweisung kann durch ein Label markiert werden:
Label: Anweisung
Alle Labels müssen außerdem in dem Block, in dem sich die markierte Anweisung befindet, im Labeldeklarationsteil aufgeführt werden. Im report wird definiert, daß der Labeldeklaratonsteil die erste Deklaration eines Blockes bilden muß. In Pascal 2.0 ist wie bereits erwähnt die Reihenfolge der Deklarationsteile frei wählbar. Eine Labeldeklaration hat folgende Syntax:
LABEL Label, Label, ... , Label;
Sinnvolle Beispiele für Sprünge findet man nur in komplexen Programmen, bei denen eine Ausnahmebehandlung erforderlich wird. In kleinen Programmen läßt sich die Sprunganweisung ohne Mehraufwand problemlos vermeiden. Daher ist das folgende Programmstück nur als ein künstliches Beispiel zu betrachten (BASIC läßt grüßen):
PROGRAM SPRUNG(OUTPUT); LABEL 1,7,8; VAR X: INTEGER; BEGIN WRITELN('Punkt 1'); GOTO 7; 1: IF X=0 THEN GOTO 8; WRITELN('Punkt 2', X); X:= X-1; GOTO 1; 7: X:=5; GOTO 1; 8: WRITELN('Punkt 3'); END.
Das Programm erzeugt folgende Ausgabe:
Punkt 1 Punkt 2 5 Punkt 2 4 Punkt 2 3 Punkt 2 2 Punkt 2 1 Punkt 3
Bei Sprüngen muß die durch Prozeduren, Funktionen und zusammengesetzte Anweisungen gebildete Blockstruktur eines Pascal- Programmes beachtet werden:
Andererseits ist es erlaubt, aus einer geschachtelten Prozedur zu einer Marke in einem umfassenden Block zu springen. Beispiele für diese Regeln bei blockübergreifenden Sprüngen finden Sie in Abschnitt 4.4.2 unter dem Stichwort »Sprunganweisung«.
1. Schreiben Sie ein Programm zur Umwandlung arabischer Zahlen in römische Zahlen. Vielleicht haben Sie auch eine Idee, wie man die Umwandlung in umgekehrter Richtung realisieren kann.
2. Schreiben Sie ein Programm, das Zahlenfolgen einliest und bei der Eingabe der Zahl 999 die Summe über die Folge (natürlich ohne 999) druckt. Welche Wiederholungsanweisung ist hier angebracht?
3. Erweitern Sie das Programm 2, so daß die größte und kleinste Zahl der eingelesenen Zahlen bestimmt wird:
1 3 44 33 -20 12 999 SUMME: 73 MAXIMUM: 44 MINIMUM: -20
4. Erweitern Sie das Programm aus Abschnitt 2.8.5, indem Sie vor dem Zeichen der Funktion zunächst den Bereich der auftretenden Y-Werte bestimmen. Nachdem der maximale und minimale Y-Wert bekannt sind, können Sie die Y-Koordinaten wie die X-Koordinaten skalieren, um die Funktion auch in Y-Richtung immer bildschirmfüllend darzustellen.
5. Erstellen Sie ein Programm, das die Nullstellen einer Funktion F nach dem Intervallschachtelungsverfahren bestimmt: Der Benuter gibt als Startwerte die Intervallgrenzen L und R an, zwischen denen eine Nullstelle liegt. Dabei soll gelten:
F(L) * F(R) <= 0
d.h. zwischen L und R liegt ein Vorzeichenwechsel. Die Nullstelle wird durch sukzessive Intervallhalbierung gefunden. In Abhängigkeit vom Vorzeichen des Funktionswertes in der Intervallmitte M=(L+R)/2 wird M als rechte oder linke Intervallgrenze des folgenden Schleifendurchlaufs benutzt. Die Approximation beende man, falls die Intervallgröße kleiner als eine vom Benutzer vorgegebene Genauigkeit ist. Prüfen Sie das Programm mit der Funktion
F:= 2 * SIN(X) - COS (2 * X)
im Intervall L=0 und R=1!
6. Schreiben Sie ein Programm, das alle Primzahlen in einem vom Benutzer vorgegebenen Intervall druckt. (Eine Zahl X heißt prim, wenn sie nur durch 1 und sich selbst geteilt werden kann. 1 ist keine Primzahl). Die Geradeaus-Methode zur Programmierung besteht darin, den Divisionsrest (Operation MOD!) bei der Division der Zahl X durch alle kleineren Zahlen Y zu untersuchen. Um die Laufzeit des Programmes nicht sinnlos anwachsen zu lassen, sollten Sie sich vor der Programmierung überlegen, welche Zahlen von Anfang an als Primzahlen ausscheiden und bis zu welcher Zahl Y die Teilbarkeit geprüft werden muß.
7. Schreiben Sie ein Programm, das eine Wahrheitstabelle in der folgenden Form druckt:
A | B | A AND B --------+---------+---------- FALSE | FALSE | FALSE FALSE | TRUE | FALSE TRUE | FALSE | FALSE TRUE | TRUE | TRUEGeben Sie sich ruhig etwas Mühe bei der Formatierung. Benutzen Sie (String-)Konstanten! Besonders schön wäre es, wenn Sie zwei geschachtelte Schleifen mit booleschen Variablen A und B verwenden würden:
FOR A:= FALSE TO TRUE DO ... FOR B:= FALSE TO TRUE DO ... ...
Prüfen Sie mit dem Programm die Ergebnisse von A<B, A>B, A<=B und A>=B statt A AND B!
8. Überlegen Sie sich, wie man die Operation I MOD 7 verwenden kann, um die Ausgabe von Ergebnissen so zu steuern, daß jeweils sieben Werte in einer Zeile erscheinen:
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 ...
9. Besonders schöne Bildschirmgrafiken erhält man durch die Darstellung mathematischer Kurven, die als Zykloiden bezeich- net werden. Sie entstehen mechanisch als Bahn eines Punktes P, der mit einem Kreis vom Radius R im Abstand A vom Mittelpunkt M des Kreises fest verbunden ist, wenn dieser Kreis um einen anderen Kreis mit dem Radius R1 rollt. Ein Spielzeug zum Zeichnen dieser Bilder heißt Spirograph.
Bild 24: Parameter einer Zykloide
Natürlich lassen sich die Linien auch punktweise mathematisch berechnen: Dreht sich der Kreis um einen Winkel PHI, so befindet sich der Punkt an folgenden relativen Koordinaten zum Mittelpunkt des feststehenden Kreises M1:
X = (R + R1) * COS(PHI) - A * COS((R + R1) * PHI / R) Y = (R + R1) * SIN(PHI) - A * SIN((R + R1) * PHI / R)
Programmieren Sie diese Kurven! Für die Eingabe von R, R1, A und einer Schrittweite DELTAPHI wird eine Folge von X/Y-Koordinatenpaaren berechnet, die wie in Abschnitt 2.8.5 beim Zeichnen der Funktion mit LOCATE und DRAW zu einer zusammenhängenden Kurve verbunden werden.
Da es ein nichttriviales Problem ist, aus dem rationalen Verhältnis von R und R1 den Winkel ENDPHI zu bestimmen, bei dem sich die Koordinaten zyklisch wiederholen, und die Kurve sich schließt, sollten Sie die Berechnung einfach bei einer Tastenbetätigung des Betrachters beenden.
Beispielparameter: R = 40 20 R1 = 35 50 A = 75 75 DELTAPHI = 0.2 1
10. Etwas aufwendig ist die Beschriftung von Grafiken: Erweitern Sie das Programm zum Zeichenen einer Funktion, indem Sie z.B. die X-Achse im Bild einzeichnen und in einem festen Abstand mit den X-Werten beschriften. Am schwierigsten ist dabei die Ausrichtung der Grafik am Text, da Text im Grafikmodus nur in 8-Pixel-Schritten ausgegeben werden kann.
Um z.B. die Zahlen von 0 bis 10 jeweils 16 Pixel in Y-Richtung auseinanderstehend zu drucken kann man folgendes Programm verwenden:
PROGRAM GRAPHICTEXT(INPUT,OUTPUT,GRAPHIC); VAR I: INTEGER; BEGIN GRAPHIC(1,1); FOR I:= 0 TO 10 DO DISPLAY(1,5,24-2*I, STR(I:5:1)); REPEAT UNTIL KEYPRESSED; GRAPHIC(0); END.