202 6 7MB
German Pages 89 [96] Year 1971
de Gruyter Lehrbuch Bayer • Programmierübungen in A L G O L 60
Programmierübungen in ALGOL 60
von
Dr. Georg Bayer Unter Mitarbeit von Dipl-Ing. Lothar Potratz und DipL-Math. Siegfried Weiß
w DE
G Walter de Gruyter & Co • Berlin • New York 1971
© Copyright 1971 by Walter de Gruyter & Co., vormals G. J. Göschen'sche Verlagshandlung J. Guttentag, Verlagsbuchhandlung - Georg Reimer - Karl J. Trübner - Veit & Comp. Berlin 30. - Alle Rechte, einschl. der Rechte der Herstellung von Photokopien und Mikrofilmen, vom Verlag vorbehalten. - Satz: IBM-Composer, Fotosatz Prill, Berlin Druck: J. Schönwald KG, Berlin - Printed in Germany ISBN 3 1 1 0 0 3 5 6 2 6
Inhaltsverzeichnis
1. Einleitung 2. Einfache Elemente von Algol 2.1 2.2 2.3 2.4
Einfache arithmetische und Boolesche Ausdrücke Einfache Anweisungen Verbund und Programm Ausgearbeitete Programmbeispiele zu Kapitel 2
3. Weiterer Ausbau von Algol 3.1 3.2 3.3 3.4
Bedingte Anweisungen und bedingte Ausdrücke Laufanweisungen Blockstruktur und Verteiler Ausgearbeitete Programmbeispiele zu Kapitel 3
4. Prozeduren 4.1 4.2 4.3
Deklaration von Prozeduren Gebundene Variable, rekursive Prozeduren Ausgearbeitete Beispiele für Prozeduren
Literaturhinweise
7 10 10 13 18 20 27 27 34 37 42 58 58 64 73 90
1. Einleitung
Das Ziel der Übungen ist es, den Lernenden durch zusätzliches Arbeitsmaterial für das Programmieren in Algol zu unterstützen; es kann neben einer oder im Anschluß an eine Einfuhrung in Algol 60 verwendet werden. Durch die Übungen soll dem Leser der Umgang mit Algol 60 geläufig werden, und er soll die Formulierung von Algorithmen durch das Mitarbeiten an Beispielen erlernen. Letzteres Ziel steht dabei im Vordergrund. Für den Anfänger erweist es sich immer wieder als schwierig, eine für den Rechenautomaten verarbeitungsgerechte Rechenvorschrift zur Lösung einer gegebenen Aufgabe zu finden. Die Beherrschung der Ausdrucksmöglichkeiten einer Programmiersprache, hier der „Algorithmic language Algol 60", ist einerseits die notwendige Voraussetzung zur Formulierung eines für den Rechenautomaten eingabefertigen Programms, andererseits aber enthält die Programmiersprache naturgemäß gerade diejenigen Ausdrucksformen (z. B. Variable, Felder, Prozeduren usw.), welche die Denk- und Arbeitsweise beim Programmieren bestimmen. Wie findet man geeignete Rechenvorschriften? Ein Satz von arithmetischen Formeln zum Beispiel, welche die Existenz der Lösung eines numerischen Problems konstruktiv beweisen, ist vielleicht einfach in ein Algolprogramm umsetzbar, stellt jedoch selten einen den Fähigkeiten des Rechenautomaten gut angepaßten Algorithmus dar, ist vielleicht nicht einmal praktikabel. Ähnlich ist es mit vielen anderen Problemen, deren Lösungsverfahren aus der Theorie oder aus der Anschauung her zwar grundsätzlich bekannt sind, die jedoch erst auf eine solche Weise algorithmisch formuliert und damit programmiert werden müssen, daß sie von einem Rechenautomaten verarbeitet werden können. Es gibt in einigen Teilgebieten (z. B. Listenverarbeitung, Numerische Verfahren) typische, modellhafte Algorithmen, die systematisch studiert, angewandt und auf andere Probleme übertragen werden können. Im Rahmen dieser Übungen kann es uns nicht darum gehen, solche Wege zu beschreiten, die einer tieferen theoretischen Fundierung bedürfen. Wir wollen vielmehr den Leser zum Nachdenken und Programmieren anregen, damit er auf diese Weise eigene Erfahrungen mit Algorithmen sammelt und anzuwenden lernt. Aus diesem Grunde haben wir auch zu den Aufgaben immer eine solche Lösung angegeben, die zum Nachdenken anregt. Leider können solche Lösungen dem Leser als trickreich erscheinen; es war aber nicht unser Ziel, Programmiertricks vorzuführen (vgl. z. B. Lösung 2 in Aufgabe 3.4.9). Bei der Auswahl des Übungsstoffes haben wir numerische Standardaufgaben (z. B. den Gaußalgorithmus) und Aufgaben der unmittelbaren Praxis (z. B. Be-
8
Einleitung
rechnung eines Kurbelgetriebes) nicht in Betracht gezogen: Erstere Aufgaben gehören in die Programmbibliotheken, letztere Aufgaben soll der Leser mit den erworbenen Kenntnissen angreifen können. Anleitung zu den Übungen Wir setzen nur voraus, daß der Leser die Programmiersprache Algol kennt. (Siehe dazu die Literaturhinweise.) Der Leser bedarf keiner darüber hinausgehenden, speziellen Vorkenntnisse, insbesondere kaum mathematischer. Es sollte möglich sein, daß er die erworbenen Erfahrungen auf seinem eigenen Anwendungsgebiet verwerten kann. Der Übungsstoff ist so gegliedert, daß er ungefähr der Darstellung von Algol in Lehrbüchern entspricht. Die ersten Abschnitte eines jeden Kapitels dienen der Einübung der in den Überschriften genannten Begriffe; der jeweils letzte Abschnitt bringt ausgearbeitete vollständige Programmbeispiele, die den Stoff des betreffenden Kapitels und aller vorhergehenden umfassen. Wo es notwendig erscheint, wird der Lösungsweg einer Aufgabe schrittweise dargestellt und kann vom Leser ebenfalls schrittweise „aufgedeckt" werden. Wir empfehlen dem Leser, sich unserer Lösungen erst dann zu bedienen, wenn ihm eine eigene Lösung versagt bleibt. Seine Hauptaufgabe sollte darin bestehen, seine Lösung, die nicht falsch oder schlechter als die unsere sein muß, mit der unseren schließlich kritisch zu vergleichen. Programme und Programmabschnitte sollte er mit einem kleinen Zahlenbeispiel testen, das er selbst anstelle der Rechenanlage durchführt; dabei lernt er den Ablauf des Algorithmus kennen und findet eventuell Verbesserungsmöglichkeiten. Darüber hinaus empfehlen wir selbstverständlich auch die Benutzung eines Rechenautomaten; sichtbare Erfolge sollen den Leser stärken! Bei schwierigen syntaktischen Problemen,geben wir Erklärungen und verweisen zusätzlich auf den 'Algol Report' [AR] (Revised report on the algorithntic language Algol 60). Prozeduren zur Ein/Ausgabe sind im folgenden erklärt. Wir verwenden nur wenige Prozeduren. Daß Prozeduren bei verschiedenen Compilern verschieden erklärt sein mögen, kann den Übenden nicht stören. In der Ausgabe sind die ausgearbeiteten Programmbeispiele so angelegt, daß Druckerzeilen von höchstens 80 Anschlägen beansprucht werden. read Funktionsprozedur vom Typ real.
Wirkung eines Aufrufs: Es wird ein Zahlenwert vom Eingabemedium gelesen und die Funktion erhält diesen Wert. Anschließend steht auf dem Eingabegerät die nächste Zahl zum Lesen bereit. (Die Zahlen werden in der in Algol
Einleitung
9
üblichen Form dargestellt; voneinander getrennt werden sie durch Komma oder durch zwei (und mehr) Zwischenräume oder durch Übergang zu einer neuen Zeile.) newline(n)
Anweisungsprozedur. Wirkung eines Aufrufs: Auf dem Ausgabemedium werden soviel Übergänge auf den Beginn einer neuen Zeile gemacht, wie der Wert des Arguments angibt. Als Spezifikation von n denke man sich value n; integer n; print(x, m, n)
Anweisungsprozedur. Wirkung eines Aufrufs: Der Wert von x wird auf dem Ausgabemedium ausgedruckt, anschließend zwei Zwischenräume. Falls m = 0, n 0: Ausgabe in Gleitpunktform mit «-stelliger Mantisse nach dem Schema ±.xxxxxx 10 ± xx i_h_i ( n + 8 Anschläge) Falls Ausgabe mit Dezimalpunkt, und zwar m Stellen vor, n Stellen nach dem Dezimalpunkt nach dem Schema ± xxxx.xxxxxx i n i (m+n + 4 Anschläge). Falls m 0, n = 0: Ausgabe als ganze Zahl mit m Stellen nach dem Schema ± xxxxxxxx i_u_i (m + 3 Anschläge) Als Spezifikation für x, m, n denke man sich value x, m, n; integer m, n; real x; writetext(s)
Anweisungsprozedur. Wirkung eines Aufrufs: Die dem formellen Parameter s entsprechende Zeichenkette wird (ohne die Kettenzeichen) ausgedruckt. Als Spezifikation von s denke man sich string s;
(Die Kettenzeichen () sind in diesem Buch durch '(' und ')' dargestellt.)
2. Einfache Elemente von Algol
2.1. Einfache arithmetische und Boolesche Ausdrücke Aufgabe 2.1.1. Man ersetze folgende Ausdrücke, falls sie definiert sind, durch Zahlen: l
2
3
3/2 X 5.0 . 5 X 103 s sqrt ( 1 0 - 2) 7 sqrt (- 4.0) 9 exp (In (1)) li abs (- 1 0 2 X 0.0002) 13 entier (- 0.5)
4
6 8 io 12 14
2t 2t 2 0.5 X 10 t 3 15.0-sqrt (16 t 2) In {- 1) In (exp (- 0.2)) sign (b t 2 + abs(a) + 14) arctan ( 1.0)
Lösungsweg: Setzt man für diese leicht überblickbaren Ausdrücke die entsprechenden Zahlen ein, so spart man Rechenzeit. s,6 Die Maschine führt eine Funktionsberechnung aus. 7,8 sqrt und In von negativen Zahlen sind nicht definiert.
Lösungen: l 3 5 7 9 11 13
7.5 500.0 oder ,5103 0.1 nicht definiert 1.0 0.02 - 1
2 4 6 8 10 12 14
16 500.0 oder ,5103 - 1.0 nicht definiert -0.2 1 0.785381 . . . (7t/4)
Aufgabe 2.1.2. a, b und c seien real-Variable mit den Werten a = 1.0, b = 2.0 und c =3.0. \ und j seien integer-Variable mit den Werten i = 2 und / = 5. Ferner ist das integer array ar[1 : 2] mit den Werten ar[l]-l und ar[2]=2 gegeben.
2.1. Einfache arithmetische und Boolesche Ausdrücke
11
Man bestimme Wert und Typ folgender Ausdrücke: 1 3 5 7 9 11 13 15 17 19
(a + b)/a/b btbtc exp(a) t i ar[i] + ar[1.8] (j + ¡)/a btb ar[2] t b sign(b - i) entier(- a/j) sign(entier(- 0.3))
2 4 6 8 10 12 14 16 18
a + c/a/b b t (b t.c) exp(a t i) i t i- a+j b t ar[2] ar[2] t ar[2] sign(a/b) abs(j -r i) sign(entier(0.3))
Lösungsweg: 1-6 7 8, 9 io-i3 14,15 16 17-19
Man beachte die Vorrangigkeit. Ein Indexausdruck vom Typ real wird durch Rundung in den Typ integer umgewandelt. Verknüpfung von Operanden verschiedenen Typs! [AR 3.3.4.3] sign liefert immer einen Wert vom Typ integer. abs hat als Ergebnis immer einen Wert vom Typ real. entier ( E ) liefert die größte ganze Zahl die kleiner oder gleich E ist [AR 3.2.5],
Lösungen: l 3 5 7 9 11 13 15 17 19
1.5 real 64.0 real 7.34 real 4 integer 7.0 real 4.0 real 4.0 real 0 integer -1 integer -1 integer
2 4 6 8 10 12 14 16 18
2.5 real 256.0 real
2.71818... 8.0 real 4.0 real 4 integer 1 integer 2.0 real 0 integer
real
2. Einfache Elemente von Algol
12
Aufgabe 2.1.3. Man korrigiere die falsch gebildeten arithmetischen Ausdrücke: l 2 3
24a +102 3a 6ß (b+l)(c-l)
falsch: 24a + 102 falsch: 3 alpha/6 beta falsch: (b + 1) (c - 1) falsch: a / - 2 X c
4 5
c"2 +7
falsch: c t - 2 + 1
6
(x + 23000? b c+2
falsch: x + 2.310 +4 t 3
7 8 9 10
falsch: b/c + 2 falsch:
b a + 3 • 10n b \3/ 2s y» V [12,3' 23,4
atn-1/b
falsch: alpha + 3i0n falsch: (1/a) t 2 X (b/12,3) t 3 X (2 X s/23,4) t 4
Lösungsweg: 1-3
4,5 9 10
Der Operator „mal" kann nicht weggelassen werden. Zum Beispiel bei 24a kann es sich nicht um eine Variable handeln, sondern gemeint ist offenbar der Ausdruck „24 mala". Grundsätzlich können nicht zwei Operationen aufeinanderfolgen. Man kann 10n nicht als Zahl schreiben, da der Exponententeil keine Variable sein kann. Ein Komma in einer Gleitpunktzahl ist nicht erlaubt.
Lösungen: l
24 X a +
3 5 7 9
(b + 1) X (c - 1) c t (- 2) + 1 b/(c + 2) alpha + 3 X 10 t n
102
2 4 6 8 10
3 X alpha/ (6 X beta) (besser: 0.5 X alpha/beta) a/(- 2) X c (x + 2.3,0 + 4) t 3 a t (n - 1)/b (1/a) t 2 X (b/12.3) t 3 X (2 X s/23.4) t 4 oder: ((2 X s/23.4) t 2 X b/(12.3X a)) t 2 X b/12.3
2.2. Einfache Anweisungen
13
Aufgabe 2.1.4. Welchen Wert haben die folgenden Booleschen Ausdrücke? Deklariert seien integer x, y, z und boolean a, b. c, d, e. Die Variablen haben die Werte: x = l,y l
= 75 und a = false, b =true, c = true, d = false, e = false.
Ha
3
s 7
=4,z
X > V A V < Z
~lc=dvb3c/\e b = cvd/veD3Xx>y/z
6
x> y x> 0 = y> 0 b = c v a v x = y
8
1 5 X
2 4
x =
Z A b v y > 1
Lösungsweg: Es sind die Vorrangregeln von arithmetischen Operationen verbunden mit Relationen und logischen Operationen zu beachten [AR 3.4.6.1], Zum Beispiel ist in 7 die Vorrangigkeit durch folgende Klammerung zu ersetzen: b = |c v ((d A e) 3 ((3 X x) > y / z ) ) ) Lösungen: l 3 s 7
true false true true
2 4 6 8
false true true true
2.2. Einfache Anweisungen Aufgabe 2.2.1. Die Fehler in folgenden Anweisungen sind zu finden und zu erläutern: Es sind i, j, k Namen von integer-Variablen x, y Namen von real-Variablen a, b Namen von Feldern. 1 2 3 4
x := io- 2.5; print (i + j), 3,0); - i : = j + k; a[i] := b[k] X a[i,k];
14
2. Einfache Elemente von Algol
s k := abs(i)-i-abs (j); 6 goto 1b;
1 i := x := 1; 8 if i = j = k then goto m1;
Lösungen: 1 Die Basiszehn10 leitet den ganzzahligen Exponenten einer Gleitpunktzahl ein. Demnach kann z. B. der Wert 0.334 X 1CT22 als Zahl .334 10 -22 direkt angegeben werden, nicht zu verwechseln mit der Rechenvorschrift 0.334 X 10 t (-22). Der Wert 10~2'5 kann jedoch nur als Ausdruck gebildet werden: x := 10 t (- 2.5) oder im Rechenaufwand kürzer x := 0.01/sqrt( 10.0) [AR 2.5.1] 2 Öffnende und schließende Klammern treten hier nicht paarweise auf. Vermutlich ist print (i + j, 3, 0) gemeint. 3 Links des Ergibtzeichens darf nur eine Variable stehen, - i ist jedoch keine. Vielleicht wollte der Programmierer i := -(j + k) ausdrücken. 4 Aufgrund der eindeutigen Zuordnung von Namen zu Rechengrößen kann a nicht zugleich Name eines ein- und zweidimensionalen Feldes sein. s Die Standardfunktion abs(e) liefert einen Wert vom Typ real [AR 3.2.4]. Die Operation -r (ganzzahlige Division) darf aber nur auf Operanden vom Typ integer angewendet werden. Richtig wäre k := abs(i H- j). 6 Unmögliche Marke Ib. Als Namen für Marken sind und erlaubt. [AR 3.5.1] 7 Bei mehrfachen Zuweisungen müssen sämtliche Variablen links von := vom gleichen Typ sein. 8 Eine Verknüpfung von 3 Größen durch Vergleichsoperatoren ist nicht möglich. Richtig: rf i = j a j = k then goto m1
Aufgabe 2.2.2. Die folgenden Rechenvorschriften sind in Algol durch eine oder mehrere Anweisungen zu formulieren: l y =
r+ a- x +b x
15
2.2. Einfache Anweisungen
x
3 y = e° • sin (b • x) + 10~ 2
3
4 y = (a + b- c) 5
y
_
4.3x2 +3.2x + 17.7 x1 - 8.2xs + 0.3x3 - 2.2x + x3+x
6 y=x^ 7 S^
1
t
+l -v
2 2 |) 8 7 = 10logfx - Vlx -i n/2 falls n gerade 9 m= (integer m,n) (« +1)12 falls n ungerade
Lösungen: 1 y := c/(a X x + b) + c/x;
Ausklammern von c bringt keinen Vorteil, sondern zusätzlich eine Multiplikation. 2
sx:=sin(x); y := 0.5 X sx - 1.0/sx;
Man soll vermeiden, den Wert sin(x) zweimal zu berechnen. Typische Verhältnisse der Rechenzeiten in der Gleitpunktarithmetik sind: +,X / sin, exp 5 12 30 300 3 y := exp(c) X sin(b X x) + 10.0 t (—x); 4 y := (a t 2 + b X c) t 3; s
x2 := x t 2; y := (4.3 X x2 + 3.2 X x + 17.7)/((((x2 - 8.2) X x2 + 0.3) X x2 - 2.2) X x);
Durch Anwendung des Horner-Schemas wird die Anzahl der Multiplikationen verkleinert. 6 y := ((x + 1) X x X x + 1) X x + 1; 7 y := ((a/x + b)/x + c)/x + d;
Auch hier liegt die gleiche Verarbeitung wie beim Horner-Schema vor (Polynom in 1/x). Wegen der längeren Ausführungszeit der Division (siehe 2 oben) ist noch günstiger: y := 1.0/x; y := ((a X y + b) X y + c) X y + d;
2. Einfache Elemente von Algol
16
8 x2 := x t 2; y := In(x2 - sqrt (abs(x2 - 1)))/ln(10.0); Man muß den l(Jog durch den In mit.Hilfe der Formel = ln(x)/ln(10) l0bg(x) bilden. 9 m := (n + 1)
2;
Aufgabe 2.2.3. Folgende Anweisungen sind einer kritischen Betrachtung zu unterziehen: Deklariert sind:
i, j, k als integer x, y, z als real a, b, c als integer array
1 i := sqrt(8) + 1; 2 y := x t (3/2); 3 z := a[i + 1] X b[i + 1] X c[i + 1]; 4 k := x + 1; s i := entier(j); 6 z := y X 10 t 3; 7 i := 0; a[i] := i := 1; (An welches a[? ] erfolgt Wertzuweisung? )
Lösungen: l l 3 4
Durch i := 4 wird mit weniger Aufwand dasselbe Ergebnis erzielt. y sqrt(x t 3) benötigt weniger Rechenzeit. Der Indexausdruck (i + 1) muß dreimal berechnet werden. Operanden verschiedenen Typs; besser k := x + 1.0. Bei Zuweisung an k wird gerundet. s Der Aufruf entier(j) ist überflüssig, da entier ( j ) = / 6 z := y X io3 erspart das Potenzieren. 7 Durch die mehrfache Zuweisung erhält a[0] den Wert 1 [AR 4.2.3], Aufgabe 2.2.4. Zur Ausführung folgender Aufgaben sind Programmabschnitte zu formulieren: l Die Boolesche Variable Iv ist true bzw. false zu setzen, falls x im Intervall (u, v) liegt bzw. nicht.
2.2. Einfache Anweisungen
2 Die Boolesche Variable Iv ist true bzw. false zu setzen, falls a, b, c ein pythagoräisches Zahlentripel (a2 + b2 = c2) bilden bzw. nicht. 3 Auf einem Datenträger stehen 200 Zahlen, darunter sind 100 Stück >0 und 100 Stück < 0 ; sie sollen durch Einlesen die Felder fpos, fneg [1 : 100] besetzen, getrennt nach positiven und negativen Werten. 4 Wenn k > 1, setze i = k; wenn k = 1, setze i = i - 1 und springe nach ml; wenn k < 1, springe nach m2; s
(0fürx [AR 4.1.1]. 2 Im Gegensatz zu Beispiel l ist hier eine Deklaration eingefügt; es handelt sich daher um einen [AR 4.1.1]. 3 Auch dies ist syntaktisch ein vollständiges Programm ( < Compound statement>). 4 Bei Ausführung der Anweisung a := b wird an a ein Undefinierter Wert zugewiesen, da b noch keinen Wert erhalten hat.
2.3. Verbund und Programm
Aufgabe 2.3.2. Folgende Deklarationen enthalten Fehler: 1 begin integer i;j; real a,b,c boolean b,b1,b2; end 2 begin iteger k,l; array v[-2 : +2],w[+2 : -2]; end 3 begin real pi; pi := 3.14159265; real array a1 ,a2; boolean array b1,b2[true:false]; end 4 begin integer j; boolean; integer i; string s; end
Lösungen: 1 i und j müssen durch "."getrennt sein [AR 5.1.1], Nach real a, b, c fehlt; [AR 4.1.1], Der Identifier b wird zweimal benutzt [AR 5], 2 integer ist falsch geschrieben. Es muß untere Indexgrenze < obere Indexgrenze sein; w[+2 : -2] ist daher falsch [AR 5.2.4.3], 3 Zwischen Deklarationen können keine Anweisungen stehen [AR 4.1.1], Bei a1, a2 fehlen die Grenzen [AR 5.2.1]. false bzw. true sind keine Indexgrenzen [AR 5.2.1]. 4 Bei boolean fehlt \ leere ist aber nicht möglich [AR 5.1.1], string ist kein [AR 2.3]. 2;
19
2. Einfache Elemente von Algol
20
Aufgabe 2.3.3. Welche Bildungen sind möglich? Deklariert sind: integer array ¡1, ¡2 [ 1 7 : 2 1 , - 3 : 0 , - 9 : + 9]; real array r1 [ 0 100], r2, r3 [ - 88 : 0, 0 : 88]; i
r2[2,2]
2
i1[20, 0, 0]
3
rl (0)
4
¡2[19, - 2]
5 r1[4.4] 6 r3[0,0] 7
r2[if i 1 [20, - 1, - 1 ] = 0 then - 88 eise 0, if i2[20, 0, 0] = 1 then 0 else - 88]
8 i1[i2[18, - 2, 6]] 9
r3[r1[1],r1[2]]
10 r1[abs(sin(r1[99]))] Lösungen: 1 2 3 4 s 6 7 8 9 10
falsch möglich falsch: ( ) falsch: 3. Index fehlt möglich: r1[4] (Rundung des Indexausdrucks) möglich nicht möglich, wenn 2. Index - 88 falsch: 2. und 3. Index fehlen möglich, falls ( - 88 < rl[1 ] < 0) a (ö < rl[2] < 88) möglich, da abs(sin( )) nur Werte liefert, die durch Rundung 0 bzw. 1 ergeben.
2.4. Ausgearbeitete Programmbeispiele zu Kapitel 2 Aufgabe 2.4.1. Von einem Datenstreifen sind drei verschiedene Zahlen zu lesen. Zu berechnen und auszugeben ist der Wert: ,.größte Zahl + 3 X kleinste Zahl + 2 X mittlere Zahl".
2.4. Ausgearbeitete Programmbeispiele zu Kapitel 2
Lösungsweg: /
Die Lösung wird einfach und übersichtlich, wenn man die drei Werte der Größe nach ordnet.
Lösung: 1 begin integer x, y, z, h; 2
x := read; y := read; z := read; newline(1);
3 if x > y then begin h := x; x := y; y := h end; 4
if y > z then begin h := y; y := z ; z := h end;
s
if x > y then begin h := x; x := y; y := h end;
6
print(z + 3.0 X x + 2.0 X y, 0, 6)
7
end
Bemerkung: An manchen Anlagen kann das Ergebnis in Zeile 6 schneller mit (x+y + z)X 2 . 0 - z + x berechnet werden. Eine andere Lösung wird in Aufgabe 4.3.1. angegeben.
Aufgabe 2.4.2.
Auf einem Datenträger stehen n positive ganze Zahlen ( < 106), die der Größe nach fallend geordnet sind. Die Zahlen sind sämtlich voneinander verschieden. Der Datensatz wird durch eine negative Zahl abgeschlossen. Von einer vorgelegten positiven ganzen Zahl b, die als erste eingelesen wird, ist zu entscheiden, ob und als wievielte Zahl sie in dem Datensatz steht.
Lösungsweg: / Es kommen nur Werte vom Typ integer vor. / Die Zahlen können beim Einlesen einzeln bearbeitet werden; ein Feld braucht nicht deklariert zu werden. / Da die Zahlen geordnet vorliegen, muß der Datensatz nur dann vollständig durchsucht werden, wenn alle Werte größer als b sind. / Testbeispiele machen: b kommt vor bzw. b kommt nicht vor.
21
22
2. Einfache Elemente von Algol
Lösung: 2
3 4
5 6 7 8 9 10
il 12 13
begin integer n,a,b; b := read; n := 0; newline(1); anf: n := n + 1; a := read; if a < 0 v b > a then begin print(b,6,0); writetext ('('tritt nicht auf')'); goto aus end; if a =t= b then goto anf; comment a = b; writetext ('('zahl')'); print(b,6,0); writetext ('('steht an stelle')'); print(n,6,0); aus: end
Bemerkung: Nach dem Verlassen des Programms ist i.a. das Ende des Datensatzes nicht erreicht.
Aufgabe 2.4.3.
Es sind die vier Werte a, b, c, d (mit a < b und c < d) zu lesen. Ferner sind weitere Wertepaare x, y solange einzulesen, bis das Zahlenpaar - 9999.t) - 9999.0 auftritt. Dieses Wertepaar signalisiert das Ende der Verarbeitung und ist selbst nicht mit zu verarbeiten. Die Aufgabe besteht darin, festzustellen und auszugeben 1) wie viele Wertepaare gelesen werden, 2) wie viele Wertepaare die Bedingung a < x < b und c ^ ¡ 3 )
ja
i
ja
-
y
y * \ / l + (jj) 2 für y
>x
(Sämtliche Werte seien vom Typ real.)
Losungen: 1 y := if x < 0 then 0.0 else if x > 1.0 then 1.0 else x; 2 x := a[if j >0 then i else i + 1]; 3 z := if x = 0.0 then y else if y = 0.0 then x else if x > y then x X sqrt(1.0 + (y/x) t 2) else y X sqrt(1.0 + (x/y) t 2); 3 Bayer, Programmieriibungen
3. Weiterer Ausbau von Algol
34
3.2. Laufanweisungen Aufgabe 3.2.1. In den folgenden Beispielen ist je ein Syntaxfehler (s steht für eine Anweisung). 1 2 3 4
for Iv := false, true do s; for i := 1 step 1 while Iv do s; for i := j := 0 step 2 until 30 do s; if i < 1 then goto m; for i := 1 step 1 until end do begin s; s; s; m: s; s end;
Lösungen: 1 2 3 4
Als sind true bzw. false nicht möglich. [AR 4.6.1 ]. Unmögliche Konstruktion step 1 while. Nur eine Laufvariable möglich. Sprung in eine Laufanweisung verboten.
Aufgabe 3.2.2. Wie oft wird die Anweisung s ausgeführt9 (Sämtliche Variablen sind integer.) 1 for ¡1 := a1 step 1 until b1 do for ¡2 := a2 step 1 until b2 do for ¡3 := a3 step - 1 until b3 do s; 2 for i : = 1 step 1 until 5 do for j := 1, j + 1 while j < i do for k := 1, k + 1 while k < j do s; 3 for i := 1 step 1 until 10, i + 5 while i < 65, i + 10 step 10 until 100 do s;
3.2. Laufanweisungen
Lösungen: 1 Falls bl>al *b2>a2 *a3> b3, dann (ibl -al + i ) X (b2 - a2 + 7) X (a3 - b3 + 1) mal, andernfalls 0 mal. 2 35 mal 3 24 mal
Aufgabe 3.2.3.
Man betrachte die Lösung von Aufgabe 2.4.5. und formuliere den Verarbeitungszyklus zwischen den mit vergl und w markierten Anweisungen mit Hilfe des while-Elements.
Lösungsweg: / /
In Abhängigkeit von den Werten der Variablen i und j ist der Programmabschnitt (vergl: bis w:) wiederholt zu durchlaufen. Die Kontrolle hierüber kann einer Laufanweisung mit while übertragen werden, wobei der einzusetzende Boolesche Ausdruck identisch mit dem in der mit w markierten Anweisung ist.
Lösung: for k := 0 while i < 5 A j < 1 0 do begin if a [ i ] < b [ j ] then begin i := i + 1; goto w end; if a [ i ] > b [ j ] then begin j := j + 1; goto w end; n e w l i n e d ) ; print(a[i],8,0); print(i,3,0); print(j,3,0);
i : = i + 1 ; j : = j + 1; w: end;
Bemerkung: Die Variable k muß allein zu dem Zweck eingeführt werden, um die Laufanweisung formulieren zu können.
3'
35
3. Weiterer Ausbau von Algol
36
Aufgabe 3.2.4. Es liege ein Feld real array a[1 : n] vor. Die Anordnung seiner Werte ist zu „spiegeln". Dies bedeutet z. B. für das Zahlenbeispiel (n = 5 ) 4, 2, 6,1, 3 die Überführung in 3,1, 6, 2, 4. Man schreibe einen Programmabschnitt. Bereits deklariert seien: integer i, n, hi; real h; array a[1 : n];
Lösungsweg: /
Die Aufgabe besteht darin, gemäß einer Vorschrift (Spiegeln) Feldelemente umzuordnen. Dabei ist zu beachten, daß z. B. die Anweisung a[1] := a[5] den Wert von a[5] in das Element a[1 ] überträgt, gleichzeitig aber auch den ursprünglichen Wert al auslöscht. Der Wert al muß daher zunächst an eine Hilfsvariable zugewiesen werden.
/ Die Vorschrift „Spiegeln" läßt sich folgendermaßen umschreiben: Die Werte a\ sind zu vertauschen mit den Werten an_j+i von i = 1 bis falls n gerade, n 1 oder bis
^
, falls n ungerade. Der Ausdruck n
2 bringt diesen Wert.
/ Die Laufanweisung for i := 1 step 1 until n + 2 do
übernimmt zwar das richtige Fortschalten des Index; bei jedem Schritt muß jedoch zur Kontrolle, ob die Grenze erreicht ist [AR 4.6.4.2], die Division n 2 ausgeführt vermieden for iwerden. := n + 2 Dies step kann - 1 until 1 do. werden durch Lösung: for i := n + 2 step - 1 until 1 do begin h := a[i]; hi := n - i + 1; a[i] :=a[hi];a[hi] : = h end;
Aufgabe 3.2.5. Zur Tabellierung der Funktion y =
für je laufend von xa 1 + ^ arctan(x) in Schritten von xs bis xe ist ein Programm zu schreiben.
3.3. Blockstruktur und Verteiler
37
Lösungsweg: / Der Ausdruck im Nenner ist fiir jedes reelle x größer 0. I Da die obere Intervallgrenze xe aufgrund von Rundungsfehlern bei Fortschaltung der Laufvariablen nicht exakt angenommen zu werden braucht, empfiehlt es sich, den Absolutwert der oberen Grenze durch xe : = xe + 0.5 X xs heraufzusetzen. Lösung: begin real xa,xs,xe,x; xa := read; xs := read; xe := read; xe := xe + 0.5 X xs; newline(1); writetext('(' x x/(1 + 0.5 X arctan(x))')'); for x := xa step xs until xe do begin newline(1); print(x,5,3); space(6); print(x/(1.0 + 0.5 X arctan(x)), 0, 8) end end
3.3. Blockstruktur und Verteiler Aufgabe 3.3.1. Es liegt folgendes Programmstück vor: 0 begin integer i, n; real a; n := read; Q) begin integer array a[1 : n], aa[0 : n, 0 : n]; real array mac[0 : 16, 1 : 7, 0 : 10];
Welche Bildungen sind in Block Q) möglich, welche nicht? 1 a+n 2 mac[1,1] 3 a[0] 4 aa[0, n ^ 2]
s Was ist zu den Deklarationen von Block Q) zu bemerken, falls n durch Einlesen den Wert 0 erhält?
38
3. Weiterer Ausbau von Algol
Lösung: 1 2 3 4 5
unmöglich, da a hier ein Feld ist unmöglich, da mac dreidimensional ist unmöglich, da a[0] nicht existiert möglich In diesem Fall würde die unmögliche Deklaration a[1 : 0] verlangt; obere Indexgrenze < untere Indexgrenze [AR 5.2.4.3],
Aufgabe 3.3.2. Das folgende, fehlerhafte Programm liest vom Eingabemedium die Werte n
an
an . . . aln
a2i • • • >
wobei n die Kantenlänge eines Feldes a[1 : n, 1 : n] ist und die Werte Oy das Feld a besetzen. a) Was soll das Programm bewirken? Man mache sich dies mithilfe eines Zahlenbeispiels klar. b) Man korrigiere-die Fehler. c) Was geschieht im Falle n = 11 i
begin integer n;
2
n := read;
3
begin integer array a[1 : n, 1 : n];
4
integer i,j;
s
for j := 1 step 1 until n do
6
for j := 1 step 1 until n do a[i, j] := read;
7
for i := 2 step 1 until n do
8
for j : = i - 1 step - 1 until 1 do
9
begin h := a[i, j];
10
a[i,j] =a[j, i];a[j, i] :=h
11 12
end
13
for i := 1 step 1 until n do
14
begin newlined);
end
is
for j := 1 step 1 until n do
16
begin print(a[i, j], 8, 0);
17
if (j -T- 5) X 5 = j then newlined)
18
19
end
20
2i
end
3.3. Blockstruktur und Verteiler
39
Lösung: a) Die Werte des Feldes werden an der Diagonalen (die Elemente «[»,»], i = 1, .. ., n bilden die Diagonale) gespiegelt; das auf diese Weise umbesetzte Feld wird zeilenweise, zu je 5 Elementen auf einer Druckzeile, ausgegeben. b) Zeile 9: h ist nicht erklärt; integer h in Zeile 4 ergänzen. Zeile 10: richtig a[i, j] := a[j, ¡]; Zeile n : Semikolon hinter end setzen. Zeile 12 und folgende: Der innere Block schließt mit Zeile 12. In Zeile 13 und folgenden sind i, j und a nicht mehr bekannt. Entferne end in Zeile 12 und fuge end in Zeile 20 ein. Zeile 16: Zu dem begin dieses Verbundes fehlt das zugehörige end. Füge es in Zeile 18 ein. c) Für n= 1 besteht das Feld a nur aus dem Element a[ 1,1 ]. Die Laufanweisung (Zeile 7 — Zeile n ) wird nicht ausgeführt.
Aufgabe 3.3.3.
Welcher Wert wird durch die Anweisung print(a + b, 3,0) am Programmende ausgedruckt? begin integer a , b ;
a := 4; b := 5; begin integer b , c ; b : = a + 1 ; c := 2 X a; begin integer a,c;
a := b + 1; b := b + a; c := a + b end;
a := b + c end;
print(a + b,3,0) end
Lösungsweg: / Man beachte: Wird ein Name in einem Block B deklariert, und wurde er bereits in einem umfassenderen Block A deklariert, so erhält er für den Block B eine neue Bedeutung [AR 5],
40 /
3. Weiterer Ausbau von Algol Um die Übersicht zu behalten, denke man sich die Namen gemäß ihrer Blockzugehörigkeit markiert: begin integer a h b h ' (Zi :=4;bt :=5; begin integer b2, c2;.. . usw.
Lösung: *
24
Aufgabe 3.3.4. a) Man schreibe einen Programmabschnitt (Block), der abhängig vom Wert der Variablen n (0 < n < 9) die Texte null falls n = 0 eins falls n = 1 neun falls n = 9 ausdruckt. Man löse dies mit Hilfe eines Verteilers. b) Was geschieht bei Ablauf dieses als Lösung angegebenen Programmteils, falls rt < 0 oder n > 91 c) Man treffe eine geeignete Vorkehrung, so daß goto text[n + 1 ] immer dedefiniert ist. d) Die unter a) angegebene Lösung enthält einen Syntaxfehler. Welchen?
Losung: a) (1 Syntaxfehler) 1 begin integer n; switch text := mO, ml, m2, m3, m4, m5, 2 m6, m7, m8, m9; 3 4 goto text[n + 1 ]; mO: writetextCCnull')'); goto m10; ml: writetext('('eins')'); goto m10;
m8: writetext ('('acht ')'); goto ml0; m9: writetext ('('neun')') m10: end
3.3. Block struktur und Verteiler
b) Die Ausführung von goto text[n + 1] ist Undefiniert [AR 3.5.4], c) Einfügen in Zeile 3 : i f n < 0 v n > 9 then goto m10; d) Semikolon fehlt hinter writetext('Oeun')').
Aufgabe 3.3.5. Man gebe an, in welche Zeile die Sprunganweisungen in dem folgenden Programm führen, falls sie syntaktisch möglich sind. 1 begin switch s := m1, m 2 ; goto m1; 2 3 m2: 4 goto m 3 ; s begin switch s2 := m 1 , m 2 ; 6 g o t o s2[1 ];
7
goto s2[2];
8 9 10 11 12
m2: end; begin switch s2 := m l , m2, s[i]; g o t o s2[1 ]; g o t o s2[2];
13 is
m l : i := 1;goto s2[3]; m2: m3:
16 17
end; g o t o m2;
14
18 m l : 19 end
Lösung: Zeile 2: 4:
6: T.
Ii: 12: 13: 17:
goto m1 nach Zeile 18 Syntaxfehler, m3 hier nicht bekannt goto s2[1] nach Zeile 18 goto s2[2] nach Zeile 8 goto s2[1 ] nach Zeile 13 goto s2[2] nach Zeile 14 goto s2[3] nach Zeile 18 goto m2 nach Zeile 3
41
42
3. Weiterer Ausbau von Algol
3.4. Ausgearbeitete Programmbeispiele zu Kapitel 3 Aufgabe 3.4.1. Es ist ein Programm zu schreiben, das die Summe 100 s X n2 berechnet und ausdruckt. n=l
Lösungsweg: / Bevor man ein Programm zur Auswertung einer solchen Summenformel schreibt, sollte man grundsätzlich eine numerische Untersuchung voranschicken (Fehler bei Zahlendarstellung, Auslöschung von Mantissenstellen bei Subtraktion usw.). / Bei der hier notwendigen Aufsummierung von Gleitpunktzahlen könnte es auftreten, daß ein kleiner Summand zu einer bereits viel größeren Summe keinen Beitrag mehr liefert. Um dies zu vermeiden, beginnt man die Summation mit dem kleinsten Element, in der Erwartung, daß Summand und Summe von nicht sehr verschiedener Größenordnung sind. / Es bietet sich an, den für jeden Summanden erforderlichen Ausdruck e'n ausgehend von e" 100 durch Multiplikation mit e zu berechnen. Der wiederholte Aufruf der Standardfunktion exp(-n) würde eine weitaus höhere Rechenzeit erfordern.
Losung: begin integer n; real e, en, s; e := exp(1.0); en : = e x p ( - 100.0); s := 0.0; for n := 100 step - 1 until 1 do begin s := s + en X n t 2; en := en X e end; newline(1); writetext('('summe exp(- n) X n t 2, n von 1 bis 100')'); print (s, 3, 6) end
3.4. Aufarbeitete Programmbeispiele zu Kapitel 3 Aufgabe 3.4.2. Es liege ein Feld a[1 : m, 1 : n] vor. Man schreibe einen Programmabschnitt zur Ausgabe des Feldes. Es sollen jeweils s Spalten j e Seite ausgegeben werden.
Lösungsweg: / /
Das Feld muß in Teilstücke zu jeweils s Spalten zerlegt werden: Von 1 bis s, s + 1 bis 2s, 2s + 1 bis 3s usw. Zu beachten ist, daß die letzte Seite nicht s Spalten enthalten muß. Dies muß besonders berücksichtigt werden.
Lösung: w:
n1 := 1; n2 := s; if n2 > n then n2 := n; for i := 1 step 1 until m do begin newlined); for j := n1 step 1 until n2 do print(a[i, j], 6, 3) end; if n2 < n then begin n1 : = n 1 + s ; n 2 := n2 + s; newline(10); goto w end;
Aufgabe 3.4.3. Die n Werte eines Feldes a[1 : n] sind um s Plätze zyklisch rechtsherum zu schieben. (Dabei geht z. B. mit s = 2 die Besetzung eines Feldes 8 10 12 14 16 18 über in 16 18 8 10 12 14.) Man nehme an, daß s klein gegenüber n sei und verwende zur Lösung s Hilfsspeicher. a) Gesucht ist ein vollständiges Programm mit Ein- und Ausgabe. b) Wieviele Transporte von Werten (also Anweisungen der Art a [ i ] : = v [ j ] ) werden in der angegebenen Lösung gemacht?
43
44
3. Weiterer Ausbau von Algol
Lösungsweg: Anschaulich nach Skizze: 1. Schritt:
8
10 12 14 16 18 1
1
16 18 2. Schritt: 3. Schritt:
16 18
a[l : 6]
8
10 12 14
8
10 12 14
h[l : 2]
\
t 16 18
Schreibtischtests durchführen! Lösung: a) Eingabedaten: n s at a2 . . . . an l 2 3 4
begin integer n, s; n := read;s := read; begin integer array a[1 : n], h[1 : s]; integer i;
s
for i := 1 step 1 until n do a[i] := read;
6
7
for i := 1 step 1 until s do
8 9 10
h[i] := a[n - s + i]; for i := n - s step - 1 until 1 do a[i + s] := a[i];
11
for i := 1 step 1 until s do
12
a[i]:=h[i];
13
14 is 16 17 18
comment ausgabe, je 5 werte in einer zeile; newline(1); for i := 1 step 1 until n do begin print( a[i], 8, 0); if (i -r 5) X 5 = i then newline(1)
19
20 2i
end end end
b) Die Anzahl der Transporte ist (Laufanweisungen 7, 9, 11): n + s
3,4. Ausgearbeitete Programmbeispiele zu Kapitel 3
45
Diskussion: / Wie geht die Annahme, daß s klein gegen n sei, in diese Lösung ein? Die Lösung gilt für jedes s mit 1 < s < n. Jedoch kann man ein Rechtsschieben um s Plätze durch ein Linksschieben um n - s Plätze ersetzen und damit das Hilfsfeld h und die Anzahl der Transporte evtl. klein halten. / Eine kompliziertere Struktur hat ein Algorithmus, der das Schieben allein im Feld a ausfuhrt. Wir verdeutlichen dies an dem gegebenen Zahlenbeispiel. Wie in Aufgabe 2.4.6. entstehen Zyklen von Transporten (auch hier werden n Werte permutiert!). 8
10 12
14 16
18
liefert
16
10
8
14 12
18
liefert
16
18
8
10 112 12 14
/ Das Feld h braucht nur in einem kleinen Programmbereich zu existieren. Mit Einführung eines weiteren Blockes (Zeilen 6-13) hätte man dann 3 6 13
begin integer array a [ 1 : n ] ; begin integer array h [ 1 : s]; end;
Aufgabe 3.4.4. Von einem Datenträger sind n Zahlen zu lesen und so in einem Feld zu speichern, daß nach Beendigung des Einlesens eine steigend geordnete Folge vorliegt. Lösungsweg: / Das Feld muß dynamisch deklariert werden; die Länge n des Feldes muß vor der Deklaration bekannt sein, z. B. durch Einlesen. / Der sich wiederholende Zyklus besteht aus folgenden Teilen: Zahl einlesen; Index der Stelle suchen, an der die Zahl eingefügt werden muß; bereits vorhandene Werte so verschieben, daß neuer Wert eingeordnet werden kann; neuen Wert einschreiben; Fortschalten der Füllgrenze.
46
3. Weiterer Ausbau von Algol
/ Sonderfälle: Die erste Zahl kann direkt an a[ 1 ] zugewiesen werden. Wird keine Stelle innerhalb des Feldes gefunden, an der die Zahl einzuordnen ist, so ist sie größer als sämtliche bisher gelesenen und muß daher am freien Ende abgespeichert werden. Lösung: begin integer n; n := read; begin integer i, j, k, m; real h; array a[1 : n];
m := 0; comment fuellgrenze m; a[1] := read; for i := 2 step 1 until n do begin m := m + 1; h := read; for j := 1 step 1 until m do begin if a[j] > h then begin for k := m step - 1 until j do a[k + 1] := a[k]; a[j] := h; goto nexti end end; a[m + 1] := h; nexti: end; comment weitere Verarbeitung des feldes; end end
Aufgabe 3.4.5. Gegeben seien die Felder boolean array ba, bb, bc [1 : n, 1 : n]. Alle Elemente bc[i, j] des Feldes bc sind zu besetzen, und zwar ergeben sich die Werte nach folgender „Rechenvorschrift" bc[i, /] := (ba[i, 1] A bb[l, /]) V (ba[i, 2] A bb[2,/]) V ... v(ba[i, n] A bb[n, /]) Man schreibe einen entsprechenden Programmabschnitt (Block).
3.4. Ausgearbeitete Programmbeispiele zu Kapitel 3
47
Lösungsweg: / Die „Rechenvorschrift"erinnert an die eines skalaren Produktes, wobei das logische Und die Multiplikation und das logische Oder die Addition ersetzt haben. / Eine richtige Lösung ist aufgrund der „Rechenvorschrift"leicht 2
l
3
i := 1 step 1 until n do begin for integer i, j, k;
for j := 1 step 1 until n do
4
begin bc[i, j] := false;
5
for k := 1 step 1 until n do
6
bc[i, j] := bc[i, j] v (ba[i, k] a bb[k, j])
7 8
anzugeben:
end end
/ Kritik an dieser Lösung: Es erfordert hohen Rechenaufwand, das Ergebnis in einer zweifach indizierten Variablen zu erzeugen (Zeile 6)! Verbesserung: Einfache Boolesche Variable einführen. l
begin integer i, j, k; boolean bcij;
4
begin bcij := false;
s
for k := 1 bcij := bcij v (ba[i, k] a bb[k, j]);
6
bc[i, j] := bcij
6.1 7
end
/ Zahlenbeispiel rechnen! Es sollte auffallen, daß in der Laufanweisung (Zeile 5) der Wert von bcij sich nicht mehr ändern kann, sobald er true geworden ist, d. h. daß dann kein Term (ba[ ]a bb[ ]) mehr einen Beitrag liefern kann. Bessere Fassung: 1
begin integer i, j, k;
4
begin bc[i, j] := false;
s
for k := 1 step 1 until n do
6
if ba[i, k] a bb[k, j] then
6i 7
begin bc[i, j] := true; goto w end; w:
end
48
3. Weiterer Ausbau von Algol
/ Zu der schließlich angegebenen Lösung kann man entweder durch theoretische Kenntnisse kommen (Boolesche Matrizen) oder durch Versuche, den Algorithmus anders zu organisieren. Man betrachte etwa folgendes Beispiel: ba 1 0 0 0 1 0
bc (Ergebnis)
bb 0 0 1 0
1 1 0
1 0 1 0 0
1
1
( 1 f ü r true,
0
1
0
0
0
1
0
0 f ü r false)
Aufgrund der ersten Zeile von ba ergibt sich, daß nur die 1. und 3. Zeile von bb zur 1. Zeile von bc beitragen können. Aufgrund der 2. Zeile von ba ergibt sich, daß nur die 3. Zeile von bb zur 2. Zeile von bc beitragen kann. Aufgrund der 3. Zeile von ba ergibt sich, daß nur die 1. Zeile von bb zur 3. Zeile von bc beitragen kann, bc kann so zeilenweise entstehen, bb wird zeilenweise verarbeitet. Dies ist, nebenbei bemerkt, günstig für die Verarbeitung von zeilenweise auf Hintergrundspeichern liegenden Feldern. Lösung: begin integer i, j, k; for i := 1 step 1 until n do begin for k := 1 step 1 until n do bc[i, k] := false; for j := 1 step 1 until n do begin if ba[i, j] then for k := 1 step 1 until n do if bb[j, k ] then bc[i, k] := true end end
end
Aufgabe 3.4.6. Man schreibe ein Programm, welches die n-te Zeile des Pascalschen Zahlendreiecks errechnet. Eingabe: Wert n; n > 0. Ausgabe: 4-stellige Zahlen zu je 10 in einer Zeile. (Das Pascalsche Dreieck ist ein Zahlenschema, bei dem sich die Werte einer Zeile aus denen der vorhergehenden nach dem Schema des folgenden Bildes ergeben.)
3.4. Ausgearbeitete Programmbeispiele zu Kapitel 3
n=0 1 2
3 4
49
/ VN /W N S usw.
Lösungsweg:
Die n-te Zeile des Schemas enthält n + 1 Werte. Die Werte der i-ten Zeile erhält man allein aus den Werten der vorhergehenden (i-l)-ten Zeile. Es sollte also möglich sein, mit einem Feld pz[0 : n] der Länge n + 1 auszukommen, welches nacheinander die Zeilen 0,1,.. ,n aufnehmen muß. (j > 0) Das obige Schema kann auch so gezeichnet werden, daß die Besetzung des Feldes pz und die Rechenvorschrift deutlicher werden. 0
1
2
3
....
Index (j)
1
Zeile (i)
\ 1
1
1
2
'V \ ViV* 1
1
1 usw.
/ Die Besetzung zunächst nicht benötigter Plätze von pz geschieht am besten durch 1, da ohnehin (am rechten Ende) Einsen beigestellt werden müssen. / Schreibtischtest mit n = 0,1, 2, 5. Lösung: begin integer i, j, n; n := read; newlined); print(n, 8, 0); begin integer array pz[0 : n]; for j = 0 step 1 until n do pz[j] for i = 0 step 1 until n do for j = i - 1 step - 1 until 1 do pz[j] := pz[j] + pz[j - 1];
.. Ausgabe end end
4 Bayer, Programmierübungen
1;
3. Weiterer Ausbau von Algol
50
Zusatzaufgabe: Da das Schema symmetrisch ist, soll die Aufgabe so gelöst werden, daß das Feld pz nur etwa halb so lang zu sein braucht wie in der vorigen Lösung. (Man betrachte diese Zusatzaufgabe nicht unter praktischen Aspekten, sondern als Übung!) Lösungsweg: Man versuche, ein reduziertes Schema aufzuzeichnen. 0 Zeile o l 2 3
1
2
3
Index (j)
1 1 1 1 1
1^-1* 2 3 -» 3* 4 6 5 10 ^
4 s 10* usw. Die mit * versehenen Werte sind zur Bildung der jeweils nächsten Zeile notwendig. Sie haben keinen Vorgänger in der vorherigen Zeile, können also nicht aus der vorhergehenden Zeile nach dem Bildungsgesetz des vollständigen Zahlendreiecks ermittelt werden, sondern diese Werte sind Kopien ihrer linken Nachbarn. Lösung: begin integer i, j, n, h; n := read; newline(1); print(n, 4, 0); begin integer array pz[0 : (n + 1) -r 2]; pz[0]:=1; for i := 0 step 1 until n do begin for j := i -r 2 step -1 until 1 do pz[j] :=pz[j] + pz[j - 1]; pz[(i + 1) H- 2] := pz[i - 2] end (¡ + 1)^-2 = i-^2 fuer gerade i; oomment ausgabe, 10 Werte je Zeile; newline(2); h := 0; for j := 0 step 1 until n 2, (n - 1) + 2 step -1 until Odo begin print(pz[j], 4, 0); h := h + 1; it (h -MO) X 10 = h then newline(1) end end end
3.4. Ausgearbeitete Programmbeispiele zu Kapitel 3
51
Aufgabe 3.4.7. Die Aufgabenstellung 2.4.2. wird geringfügig abgeändert: Ein Feld integer array a[1 : n], besetzt mit positiven, fallend geordneten, verschiedenen ganzen Zahlen liege bereits vor. Von einem gegebenen positiven ganzzahligen Wert b ist zu entscheiden, ob er unter den a t vorkommt, und es ist, falls er vorkommt, anzugeben, an welcher Stelle i er auftritt. Es soll ein Einschachtelungsverfahren programmiert werden.
Lösungsweg: / Durch Halbierung des Intervalls der Indices (7, n) entstehen zwei Teilintervalle von a-Werten. Man hat zu entscheiden, in welchem Teilintervall b vorkommt und hat auf dieses den soeben beschriebenen Verfahrensschritt wieder anzuwenden, bis schließlich das Intervall auf nur eine Stelle zusammengezogen ist, an welcher der Wert b vorkommt oder nicht. / Zufällig kann b an der „Intervallmitte" auftreten, so daß das Verfahren abbrechen kann, noch bevor das betrachtete Intervall auf eine Stelle geschrumpft ist. / Testbeispiele: b >a[l], b=a[l], b =a[n], b b > a [ n ] und b kommt vor, a[7] > b > a [ n ] und b kommt nicht vor. / Wie „halbiert" man ein „Intervall" mit einer ungeraden Anzahl von Werten? Lösung: begin integer ia, ie, i; ia := 1; i := ie := n; if a[i] = b then goto aus; mar: i := (ia + ie) ^ 2; if a[i] = b then goto aus eise if i < ia then begin print(b, 6, 0); writetext ('(' tritt nicht auf ')'); goto fin end eise if a[i] > b then ia := i eise ie := i; goto mar; aus: fin: end
4«
print(b, 6, 0); writetext('(' steht an stelle ')'); print(i, 6, 0);
52
3. Weiterer Ausbau von Algol
Bemerkung: Die Lösung zeigt einen Block, in welchem die zur Durchführung des Verfahrens benötigten Rechengrößen ia, ie, i erklärt sind. Diese Größen (und die vorkommenden Marken) sind lokal bezüglich des Blocks, global sind a, n, b (und die Ausgabeprozeduren).
Aufgabe 3.4.8. Zwei alphabetisch geordnete Karteien sind zu einer dritten, ebenfalls alphabetisch geordneten, zu vereinigen. Für eine einfache Formulierung nehme man an, daß ein Feld x von m ganzen Zahlen, steigend geordnet, mit einem Feld.y von n ganzen Zahlen, steigend geordnet, zu einem steigend geordneten Feld z der Länge m + «zu vereinigen ist. Die Werte m, n und die Felder* undy stehen auf einem Datenträger bereit. Das Feld z ist auszugeben. (Alle Werte seien höchstens fünfstellig).
Lösungsweg: / m und n einlesen und Block mit den dynamischen Feldern x, y und z eröffnen. / Es sind die Werte xi und zu vergleichen; der kleinere von beiden wird in das Ergebnisfeld an die Stelle 1 geschrieben. / Allgemein: „Zeiger" i und/' geben an, welches die nächsten zu verarbeitenden Werte x{ und yy sind; durch einen „Zeiger" k wird das Füllen des Feldes z verwaltet. Es ist also JCj mit y} zu vergleichen, und der kleinere der beiden Werte wird Wert von z k . Die Zeiger werden geeignet fortgeschaltet. Dieser Verfahrensschritt wird so lange durchgeführt, bis alle Elemente eines der beiden Felder x odery dem Ergebnisfeld z zugeteilt sind. / Der Rest des verbleibenden Feldes ist dann nur noch an das Ergebnisfeld z anzuhängen. / Das Verfahren ist an einem Zahlenbeispiel durchzudenken. / Die Aufgabe ist in ihrer Struktur ähnlich der Aufgabe 2.4.5.
3.4. Ausgearbeitete Programmbeispiele zu Kapitel 3
Lösung: 1 2
begin integer n, m, i, j, k, I;
3
m := read; n := read;
4
begin integer array x[1 : m], y [ 1 : n], z[1 : m + n];
5
... einlesen von feld x und feld y . ..
6 7
i := j := k := 1; vergleich:
8 9 10 n
if x[i] < y [ j ] then begin z[k] := x[i]; if i = m then goto fin1; i := i + 1 end else begin z[k] := y[j]; if j = n then goto fin2; j : = j + 1 end;
12
k := k + 1; goto vergleich;
13 14
fin1: for I := j step 1 until n do begin k := k + 1; z[k] := y[l] end; goto schluss;
is
fin2: for I := i step 1 until m do begin k := k + 1; z[k] := x[l] end;
16
17
schluss:
18
. . . ausgeben von feld z . . .
19
20
end
end
Bemerkung: / Werden die Felder x und j (z. B. im Rahmen eines umfangreicheren Problems) nach dem Einfüllen in das Feld z nicht mehr benötigt, dann spart man Speicherplatz mit folgender Blockstruktur: 4 4.1
|- begin integer array z[1 : m + n]; begin integer array x[1 : m], y[1
5-18 18.1
-end
n];
54
3. Weiterer Ausbau von Algol
/ Eine statisch kürzere und sehr kompakte Formulierung an Stelle der Zeilen 13-I6 lautet: 13,14 fin 1: for j := j step 1 until n do z[m + j] := y[j]; goto schluss; is,i6 fin2: for i := i step 1 untilmdo z[n + i] := x[i];
Der Leser mache sich an einem Beispiel die Wirkung dieser Laufanweisungen klar.
Aufgabe 3.4.9.
Es liege ein Feld a mit n ganzen Zahlen vor, für die gilt: ai < a2 a [ l + 1] then a[l] := a[l + 1] else goto aus end
in: aus:
else for I := i step - 1 until 1 do if ai < a[l - 1 ] then a[l] := a[l - 1 ] else goto aus; a[l] := ai;
.. . ausgeben des feldes
a...
end end
/ Ein Schreibtischtest mit einem Beispiel @ i = 4 und Feld a liefert das richtige Ergebnisfeld
1
3
1
2
4
2
5
Man darf daraus aber noch keineswegs schließen, daß dieses Programm nun auch für alle Fälle richtig ist. / Führt man diesen Test mit einem Beispiel ® i = 5 = n und Feld a
2
4
aus, so stellt man fest, daß a[i + 1 ] nicht definiert ist. / Man kann für den Fall i = n die kritische Abfrage mit if i = n then goto in
umgehen. Das Beispiel © wird dann richtig gelöst. / Wandelt man die erste Abfrage in if ai < a[i - 1] then
ab, wird zwar der Fall i = n richtig, aber nun ist a[i - 1 ] im Fall i=l definiert. / Bei einem Beispiel © i = 3 und Feld a
2
3
4
nicht
5
ist in der Laufanweisung bei Marke in beim Schritt 1 = 1 das Element a[l - 1 ]
56
3. Weiterer Ausbau von Algol
nicht definiert. Es stellt sich heraus, daß alle Fälle ai gleich kleinster bzw. größter Wert besonders betrachtet werden müssen. / Für einen Schreibtischtest stelle man Datensätze für folgende 9 Testfälle zusammen: i = 1, 1 a [ l - 1] then goto aus else a[l] := a[l - 1]; a[1 ] := ai; goto schluss; end;
17
aus:
is
schluss:
19 20 21
a[l] := ai;
. . . ausgeben von a . . . end end
Bemerkung:
/ Die Abfrage if i = 1 then goto i 1 kann weggelassen werden. Sie macht aber das Programm für den Leser übersichtlicher. / In den vorhergehenden Lösungen mußten die Fälle i = l,i = n, ai ist kleinster Wert und ai ist größter Wert besonders beachtet werden. Wir erhalten eine einfachere Verarbeitung, wenn wir das gegebene Feld a in ein erweitertes Feld a[0 \n + i ] mit a[0] = ai -1.0 und a[n + 7] = ai einbetten.
3.4. Ausgearbeitete Progiammbeispiele zu Kapitel 3
57
/ Beim Vergleich der Laufanweisungen 8 und 13 kann man Ähnlichkeiten feststellen. Wenn es gelingt, die Schrittweite s mit den Werte +1 bzw. - 1 und die obere Grenze vorher allgemein zu berechnen, dann kommt man mit einer Laufanweisung aus. In diesem Punkte wird dem Leser unsere Lösung 2 trickreich erscheinen. / Man achte darauf, daß die Schrittweite nicht 0 wird. Lösung 2: l 2 3 4 s 6
begin integer i, n, I, lend, s; real ai; boolean b; n := read; i := read; begin array a [0 : n + 1 ]; for I := 1 step 1 until n do a[l] := read; ai := a[n + 1 ] := a[i]; a[0] := ai - 1.0; if a[i - 1 ] = ai then goto aus;
7
s : = s i g n ( a i - a[i - 1 ] ) ;
8 9 10 11 12 13 14
if s = 1 then begin lend := n; b := true end else begin lend := 1; b := false end; for I := i + s step s until lend do if ai < a[l] = b then begin a[l - s ] := ai; goto aus end else a[l - s] := a[l]; a[lend]:=ai; aus:
is
. . . ausgeben von a . . .
16 17
end
end
Bemerkung: / Das Programm in Lösung 2 ist statisch kürzer geworden. Dagegen wird sich aber die Rechenzeit geringfügig erhöhen, da zusätzlich die Äquivalenz in der Laufanweisung 10 notwendig wurde. / Bei vielen Beispielen kann eine zeitoptimale und eine speicheroptimale Lösung gefunden werden, über deren Verwendung: von Fall zu Fall entschieden werden muß. Oft muß man sich auch für eine Zwischenlösung entscheiden, wenn z. B. Rechzeit und Speicherplatz „gespart" werden müssen.
4. Prozeduren
4.1. Deklaration von Prozeduren Aufgabe 4.1.1. Folgende Deklarationen von Prozeduren enthalten Fehler: 1
procedure p(m, x, m, y); integer m; real x, y;
2
procedure p(a, b, ' ( V ) ' ) real a, b; string s;
3
boolean procedure p(i, a[i]); value i; integer i; array a;
4
integer procedure p(m, n, a, I); value m, n; integer array a; label I;
s
real procedure p(m, x, y, q, s); value m, x, y; integer m; real x, y; real procedure p, q; switch s;
6
real procedure p(x, n); value n; integer n; real x; begin integer i;
P :=x; for i := 2 step 1 until n do p := (p + 1 ) X x end;
Lösung: 1 2 3 4 s 6
m tritt zweimal als formeller Parameter auf. ' ( ' s ')' i s t ein und kein < identifiery. a[i] ist kein . m und n sind nicht spezifiziert. Ein formeller Parameter p, spezifiziert als real procedure, existiert nicht. Steht im Prozedurkörper der Prozedurname rechts von := (hier p := (p + 1 ) . . . ), dann handelt es sich um einen rekursiven Aufruf der Prozedur, und es müßten hier Parameter mitgegeben sein. Als Rechengröße kann der Prozedurname nicht benutzt werden.
4.1. Deklaration von Prozeduren
59
Aufgabe 4.1.2. Welche Aufrufe sind erlaubt? Deklariert sind nur: integer m, n; real u, v; integer array a[1 : 100], b [ 0 : 10, 0 : 20]; real array c, d[1 : 40], e[1 : 20, 1 : 20]; real procedure p1 (x); value x; real x; p1 := (x + 1.0) X exp(x); real procedure p2(x, y ) ; value x, y ; real x, y ; p2 := x t 2 + y t 2; procedure p3(xa, xs, xe, p); value xa, xs, xe; real xa, xs, xe; real procedure p; begin real x; xe := xe + 0.5 X xs; for x := xa step xs until xe do begin newline(1); print(x, 6, 3); print (p(x), 6, 3) end;
end
procedure p4(x, y, p, q); real x, y; real procedure p, q; begin y : = q ( x , y ) ; x := p(x) end; integer procedure p5(i, c); value i; integer i; integer array c; p5 := c[i - 1] + c[i] + c[i + 1]; procedure p6(m, n, a, b); value m, n; integer m, n; array a, b; begin integer i ; for i := m step 1 until n do b[i] := a[i] end;
Aufrufe: l
u := p1 ( - 13.4)
2
u:=p1(x)
3
p4(u, v, p1 )
4
m := p5(5, d)
s
p3(0,0.01, 0.8, sin/
6
p 6 ( 3 , 10, c, d)
7
p4(5,5,p1,p2)
8
n := p2{p1(u), p1(v))
9
p3(u, 0.1 X (v - u), v, p i )
io
n := p 5 (u, b)
il
p6(u, v, b, e)
12
print(p5(3.8, a), 4, 0)
13
v:=p1(p1(u))
14
u : = p 2 ( p 4 ( u , v, p i , p2))
60
4. Prozeduren
Lösungen: 1 Erlaubt. 2 x ist nicht deklariert. 3 Ein Parameter fehlt. 4 Der Typ des Feldes d ist real, für den zweiten Parameter ist dagegen integer array spezifiziert. s Erlaubt. 6 Erlaubt. 7 An die formellen Parameter x und y werden Werte zugewiesen; Konstanten können daher hier nicht eingesetzt werden. 8 Erlaubt. 9 Erlaubt. 10 Die Prozedur p5 verarbeitet eindimensionale Felder, b ist jedoch zweidimensional. n Die Dimensionen der Felder b und e passen nicht, b ist außerdem von falschem Typ. 12 Erlaubt, 3.8 wird gerundet. 13 Erlaubt. 14 Ein Parameter fehlt, p 4 ( . . . ) ist kein Ausdruck. Aufgabe 4.1.3. Was ist zu folgenden Prozeduren zu bemerken? 1
procedure null(m, n, a); value m, n; integer m, n; integer array a; begin integer i, j, m, n; for i : - 1 step 1 until m do for j := 1 step 1 until n do a[i, j] := 0 end;
2
procedure null(m, n, a); value m, n; integer m, n; integer array a; for i := 1 step 1 until m do for j := 1 step 1 until n do a[i, j] := 0;
3
procedure such(i, max, n, a); value i, n, max; integer i, n; real max; array a; begin integer j; i := 1 ; max := a[i]; for i := 2 step 1 until n do if a[j] > max then begin max : = a[i]; i := j end end;
4.1. Deklaration von Prozeduren
4
61
real procedura fkt(x, y, z); real x, y, z; fkt := x X (x + y + z) + y X (x + z) + z X (x + y);
Lösungen: 1
Die Prozedur enthält syntaktisch keine Fehler. Die Variablen m und n in den Laufanweisungen sind lokal deklariert, haben also nichts gemeinsam mit den formellen Parametern m und n. Diesen lokalen Größen m und n werden keine Werte zugewiesen. Der Aufruf der Prozedur hat daher eine Undefinierte Wirkung.
2
In dieser Prozedur werden globale Variable i und j als Laufvariable benutzt. Dies ist grundsätzlich möglich; die Prozedur kann dann aber nur in Programme eingebaut werden, in denen diese Variablen verfügbar sind.
3
Die Prozedur bestimmt das größte Element eines Feldes und dessen Index. Diese beiden Werte werden an value-spezifizierte Parameter i und max zugewiesen, damit also an nur lokal bekannte Größen. Bei einem Aufruf z.B. such(ind, h, m, b) erhalten ind und h keine Werte.
4
Innerhalb der Prozedur werden nur die Werte der aktuellen Parameter benötigt; sie sollten daher auch durch „call by value" (Wertaufruf) eingebracht werden: value x, y, z.
Aufgabe 4.1.4. In dem folgenden Programm soll bei Aufruf der Prozedur p innerhalb der Prozedur p nach falll oder fall2 verzweigt werden, (s steht für eine beliebige Anweisung). Die Marken falll und fall2 kommen nur in der Prozedur p vor. begin integer n;array a[1 : 15]; procedura p(i, x, lab); value i; integer i; array x; label lab; begin goto lab; fall1:s;s;s; fall 2: s; s;s; end; s;s; s; p(n, a, fall2); s; s;s; end 1 2
Welchen Verstoß gegen Algol enthält der Aufruf p(n, a, fall2>? Wie muß die Prozedur geändert werden, damit das Ziel des Aufrufs (Verzweigung nach fall2) erreicht wird?
62
4. Prozeduren
Lösung: 1 2
Die Marke fall2 ist nur innerhalb der Prozedur bekannt; in dem Block, in dem der Aufruf steht, ist sie dann unbekannt. [AR 4.1.3] In der Prozedur kann switch faii := fall 1, fall2 deklariert werden. Als dritter Parameter ist der Index für einen Verteileraufruf mitzugeben. procedure p(i, x, j); value i, j; integer i, j- array x; begin switch fall := falU, fall2; goto fall[j];
fall 1: s; s; s; fall 2: s; s; s; end; Aufruf: p(n, a, 2);
Aufgabe 4.1.5. Die unter 3.4.2. formulierte Aufgabe (Ausgabe eines zweidimensionalen Feldes) ist als Anweisungsprozedur zu schreiben.
Lösungsweg: / Als Parameter sind erforderlich: m, n Spalten- bzw. Zeilenlänge des Feldes, a Name des Feldes, s Anzahl der Spalten je Seite. / Die Parameter m, n, s bringen nur Werte in die Prozedur ein. / Sämtliche im Programmabschnitt (s. 3.4.2.) vorkommenden Hilfsgrößen sind zweckmäßig lokal zu deklarieren. / So vorbereitet, kann der Programmabschnitt aus 3.4.2. ohne Änderungen als Prozedurkörper übernommen werden.
Lösung: procedura feldaus(m, n, a, s); value m, n, s; integer m, n, s; array a; begin integer i, j, n1, n2; n1 := 1; n2 := s;
4.1. Deklaration von Prozeduren
if n2 > n then n2 := n; for i := 1 step 1 until m do begin newline(1); for j := n1 step 1 until n2 do print(a[i, j], 6, 3) end; if n2 < n then begin n1 : = n 1 + s; n2 : = n 2 + s; newlineCIO); goto w end
w:
end;
Aufgabe 4.1.6.
Die unter 3.4.8. formulierte Aufgabe (Mischen zweier steigend geordneter Folgen) ist als Prozedur zu schreiben.
Lösungsweg: /
/ /
Erforderliche Parameter: m, n Längen der gegebenen Felder x, y Namen der gegebenen Felder z Name des Ergebnisfeldes m und n bringen nur Werte in die Prozedur ein. Lokal wird für jedes der drei Felder eine integer-Variable zur Indexverwaltung benötigt.
Lòsung: procedure misch(m, x, n, y, z); value m, n; integer m, n; integer array x, y, z; begin integer i, j, k, I; i := j := k := 1;
63
4. Prozeduren
64 vergleich: if x[i]b vorausgesetzt) und 2) ggt(a, b) =ggt(b, r(a, b)), wobei r der Rest bei der Teilung b in a ist, also der kleinste positive Wert r ist, für den gilt a = q X b + r Gemäß Eigenschaft 2) kann die Bestimmung eines ggt zweier Werte a, b zurückgeführt werden auf die Bestimmung desgg? zweier kleinerer Werte. Wendet man dieses Zurückfuhren fortgesetzt an, dann muß einmal der Fall eintreten, daß der zweite Operand inggt(b*, r(a*, b*)), ein Rest r(a*, b*), Null wird und somit nach Eigenschaft 1) der ggt bekannt wird. Es ist Erfahrung nötig, den Algorithmus in der Form, wie er in Aufgabe 4.3.6. angegeben ist, zu entwickeln. Denn ein Versuch der folgenden Art führt dabei nicht unmittelbar zum Ziel ggt(a, b) =ggt(b, r(a, b)) = ggt(r(a, b),r{b,r(a,b))) = ggt(Kb, r(a, b)),. .. ) Algol gibt uns aber die Möglichkeit, bei der Erklärung der Rechenvorschrift (Prozedur) die zu erklärende Rechenvorschrift (Prozedur) selbst aufzurufen, genauso wie es Eigenschaft 2) in unserem Beispiel angibt, integer procedura ggt(a, b); value a, b; integer a, b; begin integer r; r := a - (a -5- b) X b; ggt := if r = 0 then b eise ggt(b, r) end; Eine noch dichtere Formulierung ist möglich: integer procedura ggt(a, b); value a, b; integer a, b; ggt := if b = 0 then a eise ggt(b, a - a -r b X b); (Nebenbei bemerkt darf auch a < b sein. Der Leser verifiziere dies an einem Zahlenbeispiel.)
69
4.2. Gebundene Variable, rekursive Prozeduren
Das Wesen solcher rekursiver Prozeduren kann anschaulich so beschrieben werden: „Die Lösung einer Aufgabe besteht in der Zurückführung (Rekursion) auf die gleiche Lösung einer weniger umfangreichen Aufgabe. Die sukzessive Rekursion kommt dadurch zum Ende, daß der Aufgabenumfang ausgeschöpft wird." Von dieser Art sind die Aufgaben 4.2.4. und 4.2.5. Den Ablauf einer rekursiven Prozedur nachzuvollziehen ist mühsam, wenn viele Rekursionsschritte zu machen sind. Wir versuchen, den Ablauf für ggt(15,9) zu skizzieren. r1 :=15-(15 ggt1 := if 6=0 .
+ 9)X9\ then 9 eise
(^=6) ggt2{9,6)\
'
2
r := 9 - (9 + 6) X 6; _ ggt2 := if 3 = 0 then 6 else,gg?3(6,i); r3 :=6-(6 + 3)X3; _ ggt3 := if 0 = 0 then 3 eise — ;
(r2 = 3) (r3 =0) (ggt3 =ggt2 =ggtl = 3)
Aufgabe 4.2.4.
Eine Prozedur real procedure max (a, n); value n; integer n; array a ; . . .
fur Bestimmung des größten Wertes der Feldelemente von a ist rekursiv zu erklären.
Lösungsweg:
Die Aufgabe ist klar, falls n = 1: Das Maximum ist a[l ]. Ist n > 1, so bestimme man zunächst den größten unter den ersten n -1 Werten und vergleiche diesen mit dem n-ten Wert.
70
4. Prozeduren
Lòsung: real procedure max(a, n); value n; integer n; array a; begin real h; if n = 1 then max := a[1] else begin h := max(a, n - 1); max := if h < a[n] then a[n] else h end end;
Aufgabe 4,2.5.
Man gebe eine rekursiv erklärte Anweisungsprozedur an, womit die n-te Zeile des Pascalschen Zahlendreiecks ermittelt wird (vgl. Aufgabe 3.4.6.). procedure pascal (pz, n); value n; integer n; integer array pz;
Lösungsweg: Folgender Gedanke beschreibt bereits die rekursive Erklärung: Um die n-te Zeile zu erhalten (n > 0), verschaffe man sich die (n - l)-te Zeile und wende auf diese die in Aufgabe 3.4.6. skizzierte Bildungsvorschrift für die n-te Zeile an; die nullte Zeile besteht aus der Variablen pz[0] mit dem Wert 1. Lösung: procedure pascaKpz, n); value n; integer n; integer array pz; begin integer j; if n = Othen pz[0] := 1 eise begin pascaKpz, n - 1); for j := n - 1 step - 1 until 1 do pz[j]:=pz[j]+pz[j-1]; pz[n] := 1 end end;
4.2. Gebundene Variable, rekursive Prozeduren
71
Ein Programm der Art begin comment compound n;
s; begin comment compound n - 1;
s;
begin comment compound n - 2; s
N
" .begin comment compound 1; ss
^end 1; end'n - 2; end n - 1; end n;
ist für allgemeines n nicht möglich, (s und ss stehen für evtl. mehrere Anweisungen.)
Die gleiche Wirkung wie obiges „Programm " hat jedoch ein Aufruf der rekursiv erklärten Prozedur procedure comp(n); value n; integer n; begin
s; if n > 1 then comp(n - 1) else begin ss end end;
Es ist hier möglich, in jede Rekursionsstufe i noch gewisse Werte a, einzuführen, die insgesamt in Gestalt eines Feldes a als Parameter mitzugeben wären. Für eine Konstruktion dieser Art siehe die folgende Aufgabe.
72
4. Prozeduren
Aufgabe 4.2.6. Deklariert seien: integer array g, i[1 : 3 ] ; procedure ss; procedure for(n, a); value n; integer n; integer array a; begin integer j; if n = 0 then ss else for j := 1 step 1 until a[n] do begin ¡[n] := j; for(n - 1, a) end end;
Wie wirkt der Aufruf for(3, g) ? (Für eine praktische Anwendung stelle man sich vor, daß ein Aufruf abhängige der Prozedur ss eine von den Indices i'[7], i{2\ /[5] Verarbeitung bewirkt).
Lösungsweg: Man versucht zunächst, den Ablauf für for(3, g) zu skizzieren: if 3 = 0 then else f o r / ' : = 7 step 7 until g[3]
do
begin /[J] : = j l ; f o r l ( 2 , g )
t
!==»
'
if 2 = 0 then else for j 2
:= 1 step 1 until g[2]
do
begin i[2] : = j 2 ' , f o r 2 ( l , g ) if 1=0
then else
for/ 3 := 1 step 1 until g[l~\ do
begin ¡'[7] :=j 3
f
,for 3(0,g)
if 0 = 0 then ss else end
end
end
'
4.3. Ausgearbeitete Beispiele für Prozeduren
Lösung: Der Aufruf for(3, g) hat die gleiche Wirkung wie die Anweisung for ¡[3] := 1 step 1 until g[3] do for i[2] := 1 step 1 until g[2] do for i[1] := 1 step 1 until g[1] do ss; Mit Hilfe der Prozedur for gelingt es also auszudrücken, daß n ineinander geschachtelte Laufanweisungen auszuführen sind.
4.3. Ausgearbeitete Beispiele für Prozeduren Aufgabe 4.3.1.
Es ist eine abgewandelte Lösung der Aufgabe 2.4.1. anzugeben, in der eine Prozedur procedure vert (a, b) die Werte zweier Variablen vergleicht und gegebenenfalls vertauscht.
Lösung: begin integer x, y, z; procedure vert (a, b); integer a, b; begin integer h; if a > b then begin h := a; a := b; b := h end end vert; x := read; y := read; z := read; vert (x, y); vert (y, z); vert (x, y); print (z + 3 X x + 2 X y, 6, 0) end
Bemerkung: Der Leser betrachte diese Aufgabe als Übung zum Aufruf einer Prozedur und nicht unter praktischen Gesichtspunkten.
73
74
4. Prozeduren
Aufgabe 4.3.2.
Man schreibe vier kleine nützliche Prozeduren: 1
Eine integer procedure even(n), die den Wert (- 1) t n liefert (n integer).
2
Eine real procedure arcsin(x), die den Wert arcsin(x) liefert (x real, - 1