Prof. aa Dr. J. Giesl Programmierung WS14/15 C. Aschermann, F. Frohn, J. Hensel, T. Ströder Allgemeine Hinweise: Die Hausaufgaben sollen in Gruppen von je 2 Studierenden aus der gleichen Kleingruppenübung (Tutorium) bearbeitet werden. Namen und Matrikelnummern der Studierenden sind auf jedes Blatt der Abgabe zu schreiben. Heften bzw. tackern Sie die Blätter! Die Nummer der Übungsgruppe muss links oben auf das erste Blatt der Abgabe geschrieben werden. Notieren Sie die Gruppennummer gut sichtbar, damit wir besser sortieren können. Die Lösungen müssen bis Mittwoch, den 12.11.2014 um 15:00 Uhr in den entsprechenden Übungskasten eingeworfen werden. Sie nden die Kästen am Eingang Halifaxstr. des Informatikzentrums (Ahornstr. 55). Alternativ können Sie die Lösungen auch vor der Abgabefrist direkt bei Ihrer Tutorin/Ihrem Tutor abgeben. In einigen Aufgaben müssen Sie in Java programmieren und.java-dateien anlegen. Drucken Sie diese aus und schicken Sie sie per E-Mail vor Mittwoch, dem 12.11.2014 um 15:00 Uhr an Ihre Tutorin/Ihren Tutor. Stellen Sie sicher, dass Ihr Programm von javac akzeptiert wird, ansonsten werden keine Punkte vergeben. Aufgaben, die mit einem markiert sind, sind Sonderaufgaben mit erhöhtem Schwierigkeitsgrad. Sie tragen nicht zur Summe der erreichbaren Punkte bei, die für die Klausurzulassung relevant ist, jedoch werden Ihnen die in solchen Aufgaben erreichten Punkte ganz normal gutgeschrieben. Tutoraufgabe 1 (Pilze): In dieser Aufgabe beschäftigen wir uns mit dem berühmten Gaunerpärchen Bonnie und Clyde. Wenn die beiden nicht gerade Banken ausrauben, gehen sie gerne im Wald Pilze sammeln (bzw. klauen). Wir verwenden hier die Klassen Main, Mensch und Pilz, die Sie auf der Homepage herunterladen können. Jeder dieser (beiden) Menschen hat einen Korb, in den eine feste Anzahl von Pilzen passt. Weiterhin hat jeder Mensch einen Namen. Wie Sie in der Klasse Mensch sehen können, gibt es hierfür drei Attribute. Das Attribut anzahl gibt hierbei an, wie viele Pilze bereits im Korb enthalten sind. Zu jedem Pilz kennen wir den Namen. 1
a) Vervollständigen Sie die Klasse Main wie folgt: Ergänzen Sie an den mit TODO a.1) markierten Stellen den Code so, dass die Variablen steinpilz, champignon, pfifferling auf Pilz-Objekte mit passenden Namen verweisen. Ergänzen Sie an den mit TODO a.2) markierten Stellen den Code so, dass die Variablen bonnie und clyde auf passende Mensch-Objekte zeigen. Setzen Sie hierfür jeweils den passenden Namen und sorgen Sie dafür, dass in Bonnies Korb maximal 3 Pilze Platz haben. Bei Clyde passen 4 Pilze in den Korb. b) Gehen Sie in dieser Teilaufgabe davon aus, dass die Attribute bereits alle auf vernünftige Werte gesetzt sind. Erweitern Sie die Klasse Mensch um eine Methode hatplatz(), die true genau dann zurückgibt, wenn im Korb Platz für einen weiteren Pilz ist. Anderenfalls wird false zurückgegeben. Schreiben Sie für die Klasse Mensch eine Methode ausgabe(). Diese gibt kein Ergebnis zurück, aber gibt den Namen und eine lesbare Übersicht der von der Person gesammelten Pilze aus. Geben Sie in der ersten Zeile den Namen der Person gefolgt von einem Doppelpunkt (:) aus. Schreiben Sie pro Pilz im Korb eine weitere Zeile, in der (nur) der Name des jeweiligen Pilzes steht. Eine Beispielausgabe von einem Menschen mit Namen Gustav und einem Korb, der einen Pilz mit Namen Morchel und einen Pilz mit Namen Steinpilz enthält: Gustav: Morchel Steinpilz c) In der Klasse Main sehen Sie eine Variable wald. Schreiben Sie an die mit TODO c) markierte Stelle eine Schleife, die die Pilze im wald-array nach und nach abarbeitet. Hierbei wird zuerst überprüft, ob Bonnie Platz für einen weiteren Pilz hat. Wenn dies der Fall ist, wird der Pilz in Bonnies Korb hinzugefügt. Benutzen Sie hierfür auch das Attribut anzahl und passen Sie dieses entsprechend an. Nur wenn der Pilz bei Bonnie nicht hinzugefügt werden konnte, probieren wir den Pilz bei Clyde hinzuzufügen. Überprüfen Sie also in diesem Fall ebenfalls, ob der Korb voll ist und fügen Sie den Pilz ggf. hinzu. Wenn ein Pilz weder bei Bonnie noch bei Clyde hinzugefügt werden kann, wird der Pilz keinem Korb hinzugefügt. Rufen Sie am Ende einer jeder Schleifeniteration die Methode ausgabe() zuerst für Bonnie und anschlieÿend für Clyde auf. Geben Sie anschlieÿend eine Zeile aus, in der nur - - - (drei Bindestriche) steht. 2
Listing 1: Main.java 1 public class Main { 2 public static void main ( String [] args ) { 3 Pilz steinpilz = // TODO a.1) 4 5 Pilz champignon = // TODO a.1) 6 7 Pilz pfifferling = // TODO a.1) 8 9 Mensch bonnie = // TODO a.2) 10 11 Mensch clyde = // TODO a.2) 12 13 Pilz [] wald = new Pilz [] { steinpilz, champignon, champignon, pfifferling, 14 steinpilz, pfifferling, champignon ; 15 16 // TODO c) 17 18 1 public class Mensch { 2 String name ; 3 Pilz [] korb ; 4 int anzahl = 0; 5 1 public class Pilz { 2 String name ; 3 Listing 2: Mensch.java Listing 3: Pilz.java Aufgabe 2 (Vektoren): (2+2+1+1 = 6 Punkte) a) Schreiben Sie eine Klasse Vector mit einem Attribut, das ein Array vom Typ double ist. Ein Objekt vom Typ Vector soll einen Vektor im n-dimensionalen Raum repräsentieren. Erstellen Sie hierzu eine Methode void setdimension(int n), welche das Attribut mit einem leeren Array der Gröÿe n initialisiert, so dass der Vektor anschlieÿend benutzt werden kann. b) Erweitern Sie die Klasse Vector um eine Methode double scalarproduct(vector q), welche ein Argument vom Typ Vector erhält und das Skalarprodukt zwischen dem aktuellen und dem übergebenen Vektor als double Wert zurückliefert. D.h. für zwei Objekte p und q vom Typ Vector berechnet der Aufruf p.scalarproduct(q) das Skalarprodukt zwischen p und q. Das Skalarprodukt s zweier Vektoren (x 1,..., x n ) und (y 1,..., y n ) wird gemäÿ der folgenden Formel berechnet: s = Σ n i=1(x i y i ) Es soll 0.0 zurückgegeben werden, falls sich die Dimension der beiden Vektoren unterscheidet. (Anmerkung: Das ist keine gute Idee für echten Code, da es so zu stillen Fehlern kommt). c) Erweitern Sie die Klasse Vector um eine Methode void input(), welche den Benutzer zur Eingabe von n Zahlen auordert, diese einliest und das Array im Attribut des aktuellen Objekts mit diesen Zahlen belegt. Sollte die Dimensionsanzahl n für diesen Vektor noch nicht gesetzt worden sein, so wird die Methode unmittelbar wieder verlassen und kein Input gelesen. Hinweise: 3
Um einen double Wert einzulesen, können Sie die Methode Double.parseDouble() verwenden, die einen String als Argument erhält und den entsprechenden double Wert zurückliefert. Hinweise: Unter einigen Entwicklungsumgebungen funktioniert Konsoleninput nicht (z.b. BlueJ). Sie dürfen beliebigen Code benutzen um die Userwerte zu erfragen. Eine mögliche Klasse für Userabfragen in BlueJ ist auf der Homepage der Vorlesung veröentlicht (SimpleIO). d) Schreiben Sie eine ausführbare main Methode, welche den Benutzer auordert, zwei Vektoren einzugeben. Dazu wird er erst einmal gefragt, wieviele Dimensionen die beiden Vektoren haben sollen. Danach erst werden die beiden Vector Objekte erzeugt und eingelesen. Hinweise: Um einen int Wert einzulesen, können Sie die Methode Integer.parseInt() verwenden, die einen String als Argument erhält und den entsprechenden int Wert zurückliefert. Dann soll das Programm das Skalarprodukt der beiden Vektoren ausgeben. Benutzen Sie zur Lösung dieser Aufgabe Objekte vom Typ Vector. Beispiel: Der Benutzer git als Dimension 3 ein. Anschlieÿend gibt der Benutzer als Zahlen für den ersten Vektor 5.0, 5.0 und 0.0 ein. Anschlieÿend gibt er die Zahlen 0.0 und 1.0 und 2.0 für den zweiten Vektor ein. Das Programm gibt daraufhin aus, dass die Vektoren ein Skalarprodukt von 5.0 haben. Tutoraufgabe 3 (Spielfeld): In dieser Tutoraufgabe soll die Ausgabe eines Spielfelds als Java-Programm implementiert werden. Hierzu existiert bereits eine Klasse Feld mit einem Attribut fieldsize, das die Seitenlänge des quadratischen Spielfelds angibt. Listing 4: Feld.java 1 public class Feld { 2 3 // Seitenlaenge des quadratischen Spielfeldes 4 public static int fieldsize = 10; 5 6 // Gibt das Spielfeld aus. 7 public static void ausgabe ( 8 boolean [][] spieler1, 9 boolean [][] spieler2 ) 10 { 11 // TODO 12 13 14 15 // Fuehrt das Programm aus. 16 public static void main ( String [] args ) { 17 Feld. fieldsize = 3; 18 boolean [][] p1 = {{ true, true, true, 19 { false, false, false, 20 { false, false, false ; 21 boolean [][] p2 = {{ true, false, false, 22 { true, false, false, 23 { true, false, true ; 24 ausgabe (p1, p2 ); 25 26 4
Implementieren Sie die Methode ausgabe in der Klasse Feld. Diese Methode bekommt zwei 2-dimensionale Arrays von booleans als Eingabe, die das Spielfeld darstellen. Ein Feld (x, y) auf dem Spielfeld wird mit O beschriftet, falls nur Spieler 1 auf dieses Feld gesetzt hat (d.h., falls spieler1[x][y] == true). Falls nur Spieler 2 auf das Feld gesetzt hat, wird ein X angezeigt. Haben beide Spieler auf dasselbe Feld gesetzt, so wird @ ausgegeben. Freie Felder werden mit einem (Space) angezeigt. Die Ausführung der main Methode der Klasse Feld sollte dann folgende Ausgabe erzeugen. 0 1 2 -+ -+ -+ -+ A @ O O -+ -+ -+ -+ B X -+ -+ -+ -+ C X X -+ -+ -+ -+ Aufgabe 4 (Game Of Life): (2+2+4+3+(4) = 11 + (4) Punkte) In dieser Aufgabe sollen Sie ein Programm schreiben, das Conways Game Of Life (http://de.wikipedia. org/wiki/conways_spiel_des_lebens) simuliert und auf der Konsole ausgibt. Das Game Of Life ist eine Simulation, die auf einem 2-dimensionalem Spielfeld in diskreten Zeitschritten durchgeführt wird. Jede Zelle kann zu jedem Zeitpunkt t entweder lebendig oder tot sein und der Zustand im nächsten Zeitschritt t + 1 bestimmt sich durch die Anzahl lebender Nachbarn zum Zeitpunkt t. Lebende Zellen überleben, falls sie entweder 2 oder 3 lebende Nachbarn haben. Tote Zellen werden belebt, wenn sie genau 3 lebende Nachbarn haben. Unter allen anderen Bedingungen ist die Zelle im Zeitpunkt t + 1 tot. Wir werden im Gegensatz zu der Originalversion nur ein beschränktes Spielfeld betrachten und durch ein 2-dimensionales Array von boolean Werten repräsentieren (wobei true eine lebende und false eine tote Zelle darstellt). Zum Einlesen von Spielfeldern benutzen Sie bitte die auf der Webseite zu Verfügung gestellte Klasse Loader, welche die Methode static boolean[][] load(string path) zur Verfügung stellt. Diese Methode lädt die Datei, die sich am angegebenen Pfad (path) bendet, und erzeugt daraus ein 2-dimensionales Array von booleans. Eine solche Beispieldatei ist test.gol. a) Zuerst implementieren Sie eine Methode static void print(boolean[][] field), welche ein Spielfeld entgegennimmt und eine Repräsentation davon ausgibt. Dabei wird jede lebende Zelle durch ein O repräsentiert und jede tote Zelle durch _ dargestellt. Die Methode kann mit dem Beispiel in test.gol getestet werden. Das Ergebnis sollte wie folgt aussehen: OOO O O b) Erstellen Sie eine Methode static int countneighbors(boolean[][] field, int x, int y), welche für ein gegebenes Spielfeld und die Koordinaten einer Zelle (x, y) die Anzahl lebender Nachbarn bestimmt. Dabei zählen als Nachbarn von (x, y) alle Felder { (x + x o, y + y o ) x o, y o { 1, 0, 1 auÿer (x, y) selbst. Verwenden Sie zwei verschachtelte Schleifen, um alle Felder in der Nachbarschaft zu besuchen. Liegt die Zelle am Rand des Feldes, kann es vorkommen, dass einige Nachbarn nicht im Feld liegen. Für diesen Fall nehmen wir an, dass die Zellen auÿerhalb des Spielfeldes immer tot sind. c) Implementieren Sie eine Methode boolean[][] step(boolean[][] t), die ein Spielfeld übergeben bekommt und ein neues Spielfeld mit dem Zustand zum nächsten Zeitpunkt zurückgibt. Dafür wird erst ein neues 2-dimensionales Array von derselben Gröÿe wie das alte Spielfeld angelegt und dann iteriert die Methode über alle Zellen im alten Feld und überprüft, ob die Zelle im darauolgenden Zeitpunkt lebt. Diese Information wird dann an dieselbe Stelle im neuen Feld geschrieben. 5
d) Schreiben Sie eine main Methode public static void main(string[] args), so dass ein Spielfeld aus der Datei geladen wird, deren Pfad in args[0] angegeben wird. (Das Programm sollte eine Fehlermeldung ausgeben, wenn die Länge von args nicht eins ist.) Danach soll das Spiel für 6 Iterationen simuliert werden. Nach dem Laden und nach jedem Simulationsschritt soll das aktuelle Spielfeld ausgegeben werden. e)* Führen sie ihr Program mit der Datei lufgi.gol aus. Was fällt Ihnen auf? Sie erhalten 2 Bonuspunkte, wenn Sie in der Lage sind, eine Datei zu erzeugen, die nach mindestens einem Auswertungsschritt die ersten Buchstaben ihrer Vor- und Nachnamen produziert. Dies ist eine schwierigere Bonusaufgabe. Tutoraufgabe 5 (Veranstaltungen): In dieser Aufgabe soll ein Programm betrachtet werden, das bei der Organisation des Übungsbetriebs einer Lehrveranstaltung hilft. Zu einer Lehrveranstaltung gehören verschiedene Tutorien, wobei ein Tutorium aus mehreren Studenten zusammengesetzt ist. Jeder Student hat einen Namen und eine Matrikelnummer. Der Einfachheit halber verwenden wir in dieser Aufgabe genau zwei Tutorien, die als Arrays von Studenten dargestellt sind. Diese Zusammenhänge erkennt man an den entsprechenden Teilen der Klassendeklarationen: public class Veranstaltung { Student [] tutoriumeins ; Student [] tutoriumzwei ;... public class Student { String name ; int matrikelnummer ;... Startet man die main-methode in der Klasse Veranstaltung, werden zu Beginn in der Methode init() die beiden Tutorien-Arrays vom Typ Student[] mit neuen Student-Objekten gefüllt. Jedem Studenten wird dabei ein Name und eine Matrikelnummer zugewiesen. Anschlieÿend wird die Methode tauschen() aufgerufen, mit der man die Tutorien zweier Studenten einfach tauschen kann. Hierfür wird der Benutzer pro Tutorium nach einem Studenten gefragt, der tauschen möchte. Tutorium 1: 1: Hans Wurst (356789) 2: Lisa Lachs (346879) Tutorium 2: 1: Simone Schnitzel (361030) 2: Peter Pute (357001) Welcher Student aus Tutorium 1 möchte tauschen? (0 zum Beenden) 2 Welcher Student aus Tutorium 2 möchte tauschen? 1 Sobald der Benutzer die letzte Eingabe (im Beispiel 1) bestätigt, werden die beiden Studierenden (im Beispiel Lisa Lachs aus Gruppe 1 und Simone Schnitzel aus Gruppe 2) getauscht und das Ergebnis ausgegeben. Anschlieÿend ist ein weiterer Tauschvorgang möglich. Sie nden die benötigten Dateien Veranstaltung.java und Student.java auf der Webseite zur Vorlesung. Listing 5: Veranstaltung.java 1 public class Veranstaltung { 2 Student [] tutoriumeins ; 3 Student [] tutoriumzwei ; 4 5 public static void main ( String [] args ) { 6 Veranstaltung v = new Veranstaltung (); 6
7 v. init (); 8 v. tauschen (); 9 10 11 public void init () { 12 tutoriumeins = new Student [ 2]; 13 tutoriumzwei = new Student [ 2]; 14 15 Student hans = new Student (); 16 hans. name = " Hans Wurst "; 17 hans. matrikelnummer = 356789; 18 tutoriumeins [0] = hans ; 19 20 Student lisa = new Student (); 21 lisa. name = " Lisa Lachs "; 22 lisa. matrikelnummer = 346879; 23 tutoriumeins [1] = lisa ; 24 25 // Speicherzustand, nachdem ein Tutorium gefuellt wurde 26 27 Student simone = new Student (); 28 simone. name = " Simone Schnitzel "; 29 simone. matrikelnummer = 361030; 30 tutoriumzwei [0] = simone ; 31 32 Student peter = new Student (); 33 peter. name = " Peter Pute "; 34 peter. matrikelnummer = 357001; 35 tutoriumzwei [1] = peter ; 36 37 38 public void ausgabe ( Student [] tutorium ) { 39 40 41 public void tauschen () { 42 // tausche die Tutorien einiger Studis 43 int indexa ; 44 do { 45 System. out. println (" Tutorium 1: " ); 46 for ( int i = 0; i < tutoriumeins. length ; i ++) { 47 Student studi = tutoriumeins [ i ]; 48 System. out. print (( i +1) + ": " ); 49 if ( studi == null ) { 50 System. out. println (); 51 else { 52 studi. ausgabe (); 53 54 55 System. out. println (" Tutorium 2: " ); 56 for ( int i = 0; i < tutoriumzwei. length ; i ++) { 57 Student studi = tutoriumzwei [ i ]; 58 System. out. print (( i +1) + ": " ); 59 if ( studi == null ) { 60 System. out. println (); 61 else { 62 studi. ausgabe (); 7
63 64 65 66 System. out. println (" Welcher Student aus Tutorium 1 moechte tauschen? (0 zum Been 67 indexa = Integer. parseint ( System. console (). readline ()); 68 if ( indexa!= 0) { 69 System. out. println (" Welcher Student aus Tutorium 2 moechte tauschen?" ); 70 int indexb = Integer. parseint ( System. console (). readline ()); 71 72 // hole Studenten aus erster Gruppe 73 Student ausa = tutoriumeins [ indexa - 1]; 74 // hole Studenten aus zweiter Gruppe 75 Student ausb = tutoriumzwei [ indexb - 1]; 76 // speichere Studenten in erster Gruppe 77 tutoriumeins [ indexa -1] = ausb ; 78 // speichere Studenten in zweiter Gruppe 79 tutoriumzwei [ indexb -1] = ausa ; 80 81 // Speicherzustand nach Tausch Lisa Lachs und Simone Schnitzel 82 83 while ( indexa > 0); 84 85 Listing 6: Student.java 1 public class Student { 2 String name ; 3 int matrikelnummer ; 4 5 public void ausgabe () { 6 System. out. println ( name + " (" + matrikelnummer + ")" ); 7 8 a) Wir betrachten den Zeitpunkt, zu dem das erste der beiden Tutorien initialisiert und mit Studenten gefüllt wurde. In der Klasse Veranstaltung ist in der Methode init() eine entsprechende Markierung als Kommentar vorhanden. Visualisieren Sie zu diesem Zeitpunkt den Zustand des Programms, bestehend aus beiden Arrays und allen Objekte der Klasse Student. b) Visualisieren Sie den Zustand des Programs, nachdem die entsprechende Tauschoperation durchgeführt wurde. In der Klasse Veranstaltung ist in der Methode tauschen() eine entsprechende Markierung als Kommentar vorhanden. Aufgabe 6 (Wagenrennen): (1+1+2 = 4 Punkte) Wir betrachten ein kleines Programm Wagenrennen, das Streitwagen bei einem römischen Rennen verwaltet. Ein Streitwagen hat für diese Aufgabe einen Lenker und zwei Pferde. Diese Eigenschaften sind als Attribute in der Klasse Streitwagen abgebildet. Diese Zusammenhänge erkennt man an den entsprechenden Teilen der Klassendeklarationen: public class Wagenrennen { Streitwagen [] teilnehmer ;... public class Streitwagen { String LenkerName ; String PferdLinksName ; String PferdRechtsName ; 8
Der Einfachheit halber betrachten wir in dieser Aufgabe ein sehr kleines Wagenrennen, bei dem nur zwei Teilnehmer antreten. Startet man die main-methode in der Klasse Wagenrennen, werden zu Beginn die beiden Streitwagen vom Typ Streitwagen sowie ein Wagenrennen-Objekt erzeugt. Jedem Streitwagen wird dabei ein Lenker und zwei Pferde zugewiesen. Anschlieÿend wird im Wagenrennen-Objekt ein Array vom Typ Streitwagen[] angelegt und mit den beiden Streitwagen-Objekten gefüllt. Nach dieser Initialisierung startet das Rennen und ein (ueberholmanoever) wird durchgeführt. Dabei werden die Positionen der beiden Streitwagen im Array getauscht. Darüber hinaus wird allerdings auch das linke Pferd des einen Wagens mit dem rechten Pferd des anderen getauscht, um ein Ungleichgewicht zu verhindern, das unterschiedlich gute Pferde sonst verursachen könnten. Sie nden die benötigten Dateien Wagenrennen.java, Streitwagen.java und Main.java auf der Webseite zur Vorlesung. a) Wir betrachten den Zeitpunkt, zu dem die beiden Streitwagen-Objekte initialisiert wurden, aber das Streitwagen[]-Array im Wagenrennen-Objekt noch nicht angelegt wurde. In der Klasse Main existiert in der Methode main für diesen Zeitpunkt eine Markierung a). Visualisieren Sie zu diesem Zeitpunkt den Zustand des Programms. Diese Visualisierung soll alle Streitwagen- Objekte zeigen und deutlich machen, worauf die Variablen w1 und w2 zeigen. b) Visualisieren Sie den Zustand des Programms zu dem Zeitpunkt nach dem Start des Rennens, aber vor dem ersten Überholmanöver (Markierung b)). Zeigen Sie hier zusätzlich zu den Streitwagen-Objekten und den Variablen das Streitwagen[]-Array. c) Visualisieren Sie den Zustand des Programms zu dem Zeitpunkt unmittelbar nach dem ersten Überholmanöver (Markierung c)). Zeigen Sie auch hier zusätzlich zu den Streitwagen-Objekten und den Variablen das Streitwagen[]-Array. Wo ist hier ein Fehler unterlaufen und wie könnte man diesen beheben? Tutoraufgabe 7 (Verikation mit Arrays): Gegeben sei folgendes Java-Programm P: a.length > 0 (Vorbedingung) res = a[0]; i = 1; while (i < a.length) { if (a[i] > res) { res = a[i]; i = i + 1; res = max{ a[j] 0 j < a.length (Nachbedingung) a) Vervollständigen Sie die folgende Verikation des Algorithmus im Hoare-Kalkül, indem Sie die unterstrichenen Teile ergänzen. Hierbei dürfen zwei Zusicherungen nur dann direkt untereinander stehen, wenn die untere aus der oberen folgt. Hinter einer Programmanweisung darf nur eine Zusicherung stehen, wenn dies aus einer Regel des Hoare-Kalküls folgt. Beachten Sie bei der Anwendung der Bedingungsregel 1 mit Vorbedingung ϕ und Nachbedingung ψ, dass ϕ B = ψ gelten muss. D. h. die Nachbedingung der if-anweisung ψ muss aus der Vorbedingung der if-anweisung ϕ und der negierten Bedingung B selbst folgen. Geben Sie beim Verwenden der Regel einen entsprechenden Beweis an. Hinweise: Sie dürfen beliebig viele Zusicherungs-Zeilen ergänzen oder streichen. In der Musterlösung werden allerdings genau die angegebenen Zusicherungen benutzt. 9
Bedenken Sie, dass die Regeln des Kalküls syntaktisch sind, weshalb Sie semantische Änderungen (beispielsweise von x+1 = y+1 zu x = y) nur unter Zuhilfenahme der Konsequenzregeln vornehmen dürfen. a.length > 0 res = a[0]; i = 1; while (i < a.length) { if (a[i] > res) { res = a[i]; i = i + 1; res = max{ a[j] 0 j < a.length 10
b) Untersuchen Sie den Algorithmus P auf seine Terminierung. Für einen Beweis der Terminierung muss eine Variante angegeben werden und unter Verwendung des Hoare-Kalküls die Terminierung unter der Voraussetzung a.length > 0 bewiesen werden. Geben Sie auch bei dieser Teilaufgabe einen Beweis für die Aussage ϕ B = ψ bei der Anwendung der Bedingungsregel 1 an. Aufgabe 8 (Verikation mit Arrays): Gegeben sei folgendes Java-Programm P: (7+2=9 Punkte) a.length > 0 (Vorbedingung) i = 0; res = 0; while (i < a.length) { res = res + a[i]; i = i + 1; res = res / i; a.length 1 j=0 a[j] res = (Nachbedingung) a.length a) Vervollständigen Sie die folgende Verikation des Algorithmus im Hoare-Kalkül, indem Sie die unterstrichenen Teile ergänzen. Hierbei dürfen zwei Zusicherungen nur dann direkt untereinander stehen, wenn die untere aus der oberen folgt. Hinter einer Programmanweisung darf nur eine Zusicherung stehen, wenn dies aus einer Regel des Hoare-Kalküls folgt. Hinweise: Sie dürfen beliebig viele Zusicherungs-Zeilen ergänzen oder streichen. In der Musterlösung werden allerdings genau die angegebenen Zusicherungen benutzt. Bedenken Sie, dass die Regeln des Kalküls syntaktisch sind, weshalb Sie semantische Änderungen (beispielsweise von x+1 = y+1 zu x = y) nur unter Zuhilfenahme der Konsequenzregeln vornehmen dürfen. n Für n < m und einen beliebigen mathematischen Term t gilt t = 0. i=m 11
a.length > 0 i = 0; res = 0; while (i < a.length) { res = res + a[i]; i = i + 1; res = res / i; a.length 1 j=0 a[j] res = a.length b) Untersuchen Sie den Algorithmus P auf seine Terminierung. Für einen Beweis der Terminierung muss eine Variante angegeben werden und unter Verwendung des Hoare-Kalküls die Terminierung unter der Voraussetzung a.length > 0 bewiesen werden. 12