Technische Informatik für Ingenieure – WS 2010/2011 Musterlösung Übungsblatt Nr. 3 25. Oktober 2010 Übungsgruppenleiter: Matthias Fischer Mouns Almarrani Rafał Dorociak Michael Feldmann Thomas Gewering Benjamin Koch Dominik Lüke Alexander Teetz Simon Titz Simon Oberthür Seite 1(8) Aufgabe 1: (Simulation) Ziel dieser Aufgabe ist es herauszufinden, was das bereitgestellte Programm „WhatDoIDo.java“ macht. a) Laden Sie sich die Datei „WhatDoIDo.java“ von der Veranstaltungsseite (http://wwwhni.uni-paderborn.de/alg/lehre/ws-20102011/tifi/) und kopieren Sie diese in Ihr TIFI-Projekt in Eclipse. b) Führen Sie das Programm aus (Rechte Maustaste auf die Datei „WhatDoIDo.java“ → Run as → Java Application) und verwenden Sie das in der Vorlesung vorgestellte Verfahren „Simulation eines Computerprogrammes von Hand“ (siehe Kapitel 2.1 und Ergänzung 2.1). Tipp: In der Regel reicht eine einzelne Simulation nicht aus. Lösung: In den meisten Fällen, wie auch diesem, läßt sich der Algorithmus nicht nur mit einem Durchlauf des Programms bzw. mit nur einem (Paar von) Eingabewert(en) bestimmen.Deshalb führt man mehrere Simulationen mit unterschiedlichen Eingaben aus. Bei mehreren Eingabevariablen ist es allerdings sinnvoll zunächst nur eine Variable zu ändern, um die Änderungen besser beurteilen zu können. In den folgenden 4 Simulationen wurde a gleich 5 und b von 1 bis 4 verwendet: a b c a b c a b c a b c 5 1 0 5 2 0 5 3 0 5 4 0 4 0 5 4 1 5 4 2 5 4 3 5 3 0 9 3 1 9 3 2 9 2 0 12 2 1 12 1 0 14 5=5 5+4 = 9 5+4+3 = 12 5+4+3+2 = 14 Technische Informatik für Ingenieure Seite 2(8) Die Werte von a und b in der letzten Zeile wurden jeweils ausgegraut, da sie nicht mehr zum Ergebnis beitragen. Es ist zu beobachten, dass sich das Ergebnis aus a + (a-1) + (a-2) + … + (a-b+1) zusammensetzt. Analog zur Berechnung der Gaußschen Summenformel (siehe Wikipedia) läßt sich dies vereinfachen zu: f a ,b=b∗ a− b−1 2 Alternativ sind folgend vier Simulationen mit a=2 und b von 2 bis 5 dargestellt, bei denen auch negative Zahlen zum Ergebnis addiert werden: a b c a b c a b c a b c 2 2 0 2 3 0 2 4 0 2 5 0 1 1 2 1 2 2 1 3 2 1 4 2 0 0 3 0 1 3 0 2 3 0 3 3 -1 0 0 -1 1 3 -1 2 3 -2 0 2 -2 1 2 -3 0 0 2+1=3 Aufgabe 2: 2+1+0=3 2+1+0+(-1)=2 2+1+0+(-1)+(-2)=0 (Debugging) Ein Automatenhersteller entwickelt einen neuen Parkautomaten für Parkhäuser. Bevor ein Parkender das Parkhaus verlässt, berechnet der Automat den zu zahlenden Betrag. Nachdem der Parkende mindestens den zu zahlenden Betrag eingeworfen hat, soll der Automat – wenn nötig – Wechselgeld in 5-, 2- und 1-Cent-Stücken zurückgeben. So lange die Differenz aus gegebenem und zu zahlendem Geldbetrag mindestens 1 beträgt, soll Geld zurückgegeben werden. Dabei soll die Gesamtzahl der zurückgegebenen Münzen minimiert werden, indem immer die vom Betrag her größtmöglichen Münzen zurückgegeben werden. Ein Entwickler hat das Programm für die Wechselgeldberechnung bereits implementiert. Allerdings ist sein Programm noch fehlerhaft. Finden Sie mit Hilfe der Entwicklungsumgebung Eclipse die Fehler im Programm und beseitigen Sie diese. a) Laden Sie sich die Datei „Wechselgeld.java“ von der Veranstaltungsseite (http://wwwhni.uni-paderborn.de/alg/lehre/ws-20102011/tifi/) und kopieren Sie diese in Ihr TIFI-Projekt in Eclipse. Öffnen Sie die Datei durch Doppelklicken im Package-Explorer und machen Sie sich mit der Programmstruktur vertraut. Technische Informatik für Ingenieure Seite 3(8) b) Führen Sie das Programm aus (Rechte Maustaste auf die Datei oder im Editor → Run as → Java Application) und beobachten Sie was passiert. In dem Fall, dass das Programm nicht terminiert (z.B. wegen einer „Endlosschleife“), beenden Sie das Programm durch Drücken des Terminate-Buttons : c) Um die Fehler im Programm zu finden, betrachten Sie den Ablauf des Programms in der Debug-Perspektive von Eclipse und nutzen Sie den Debugger. Ein Debugger ist ein Werkzeug, mit dem der Ablauf eines Programms verfolgt werden kann. Es können Haltepunkte (engl.: Breakpoints) definiert werden, an denen der Programmablauf angehalten wird und die aktuellen Variablenwerte überprüft werden können. Ausgehend von einem Breakpoint kann der Programmablauf schrittweise verfolgt werden. Setzen Sie als Erstes einen Breakpoint (es können auch mehrere Breakpoints erstellt werden) in der Zeile 14: int rueckGeldBetrag = zuZahlen – gegeben; Dazu doppelklicken Sie in den grauen Bereich links neben der Zeile mit der linken Maustaste (durch einen weiteren Doppelklick kann der Breakpoint wieder entfernt werden). Nach dem Doppelklick ist ein blauer Kreis (der Breakpoint) zu sehen: Starten Sie nun das Programm „Wechselgeld“ im Debug-Modus: Rechte Maustaste auf „Wechselgeld.java“ im Package-Explorer oder im Editor → Debug As → Java Application: Technische Informatik für Ingenieure Seite 4(8) Geben Sie nun 33 Cent als zu zahlenden und 51 Cent als gegebenen Betrag ein. Daraufhin erscheint der folgende Dialog, in dem Sie das Häckchen vor „Remember by decision“ setzen und mit „Yes“ bestätigen: Es öffnet sich nun die Debug-Perspektive von Eclipse (Alternativ kann die Debug-Perspektive auch über: Window → Open Perspective → Other... → Debug geöffnet werden): Das Programm wurde bis zu der im Editor farblich hervorgehobenen Zeile ausgeführt. Alle Zeilen davor wurden bereits ausgeführt und haben eventuell Variablenwerte gesetzt, die im rechten oberen Fenster „Variables“ angeschaut Technische Informatik für Ingenieure Seite 5(8) (und verändert) werden können. Dort sind auch die eingegebenen Werte 33 und 51 zu sehen. Mit den „Debug“- und „Java“-Buttons rechts oben kann zwischen der normalen Java-Perspektive und der Debug-Perspektive gewechselt werden. Um das Programm weiter auszuführen, gibt es im linken oberen Fenster „Debug“ drei für uns wichtige Buttons: - Führt das Programm beginnend bei der aktuell hervorgehobenen Zeile solange aus, bis ein Breakpoint erreicht wird oder es beendet ist. - Beendet/Terminiert das Programm. - Führt die aktuell hervorgehobene Zeile aus. Führen Sie nun das Programm schrittweise durch Drücken des -Buttons oder der F6-Taste weiter aus und beobachten Sie die Varablenwerte im rechten oberen Fenster „Variables“. Versuchen Sie anhand des Programmverhaltens und der Änderungen an den Variablenwerten Fehler im Programm zu finden. d) Passen Sie nun das Programm so an, dass es sich wie erwünscht verhält (siehe Beschreibung am Anfang der Aufgabe 2). Überprüfen Sie das Verhalten des Programms mit verschiedenen Eingaben und dem Debugger. Bei der Eingabe, 33 Cent zu zahlen und 51 Cent gegeben, soll das Programm Folgendes ausgeben: Bitte geben Sie den zu zahlenden Betrag in Cent ein:33 Bitte geben Sie den gegebenen Geldbetrag in Cent ein:51 5 zurueck 5 zurueck 5 zurueck 2 zurueck 1 zurueck Hinweis: Wenn Sie den Quellcode des Programms ändern und speichern, bevor Sie das Programm beendet haben, erscheint evtl. der folgende Dialog: Technische Informatik für Ingenieure Seite 6(8) Starten Sie in diesem Fall durch Klicken auf den Button „Restart“ das Programm direkt neu oder beenden Sie es mit dem Button „Terminate“. Lösung: public class Wechselgeld { public static void main(String[] args) { // Geldbetraege einlesen Out.print("Bitte geben Sie den zu zahlenden Betrag in Cent ein:"); int zuZahlen = In.readInt(); Out.print("Bitte geben Sie den gegebenen Geldbetrag in Cent ein:"); int gegeben = In.readInt(); // Differenz, die zurueckgegeben werden muss, berechnen int rueckGeldBetrag = zuZahlen – gegeben; // rueckGeldBetrag = -18 int rueckGeldBetrag = gegeben – zuZahlen; // rueckGeldBetrag = 18 Falsch Richtig // Ausgabe bei zu wenig gegebenem Geld oder passendem Betrag (kein Rueckgeld) if (rueckGeldBetrag < 0) { Out.println("Sie haben zu wenig Geld gegeben," + " es fehlen noch " + (-rueckGeldBetrag) + " Cent!"); } else if (rueckGeldBetrag == 0) { Out.println("Kein Rueckgeld."); } /* * Solange Geld zurueckgeben, bis die Differenz zwischen * dem zu zahlenden Betrag und dem gegebenen Betrag 0 ergibt. */ while (zuZahlen > 0) // Endlosschleife, da zuZahlen immer größer 0 while (rueckGeldBetrag > 0) // Schleife bis rueckGeldBetrag gleich 0 { if (rueckGeldBetrag >= 5) { rueckGeldBetrag = rueckGeldBetrag - 5; Out.println("5 zurueck"); } else if (rueckGeldBetrag >= 2) { zuZahlen = rueckGeldBetrag – 2; // zuZahlen wird verändert: Falsch rueckGeldBetrag = rueckGeldBetrag – 2; // rueckGeldBetrag verringert um 2 Out.println("2 zurueck"); } else { rueckGeldBetrag = rueckGeldBetrag - 1; Out.println("1 zurueck"); } } } } Technische Informatik für Ingenieure Seite 7(8) Aufgabe 3: (BNF, Syntaxbäume) Auf dem zweiten Übungsblatt haben Sie für die folgenden Ausdrücke korrekte Syntaxbäume angegeben: e.) ( a * b + (-2)) g.) (a + b / c) - 2 * (3 / b) 1. Geben Sie so wie in der Vorlesung (Kapitel 2.2, Folien 44, 45) für den Ausdruck e) einen falschen Syntaxbaum an, der die dieselben Operatoren und Variablen verwendet. Dieser Syntaxbaum wertet den Ausdruck jedoch in der falschen Reihenfolge aus und führt damit so wie in der Vorlesung zu einem anderen mathematischen Ergebnis. 2. Für den Ausdruck g) geben Sie einen Syntaxbaum an, der den Ausdruck auch in einer anderen Reihenfolge auswertet als der Syntaxbaum, den Sie für g) auf Blatt 2 angegeben haben. Die Ausdrücke der Syntaxbäume sollen jedoch mathematisch äquivalent bleiben. Lösung: e) ( a * b + (-2)) + - * a b 2 Der folgende Syntaxbaum stellt diesen Ausdruck dar: a*(b + (-2)). * Obwohl im Ausdruck wie auch im Baum dieselben Operatoren und Variablen benutzt werden und die Reihenfolge von Operatoren und Variablen in beiden Ausdrücken identisch ist, entsteht ein anderer mathematischer Ausdruck. a + - b Die unterschiedliche Klammerung drückt sich im Baum durch die Anordnung der Operatoren im Baum aus: im Baum niedrig stehende Operatoren werden zuerst ausgewertet. g.) (a + b / c) - 2 * (3 / b) 2 * + b / 2 / a c 3 b Technische Informatik für Ingenieure Seite 8(8) Der folgende Syntaxbaum stellt diesen Ausdruck dar: (a+b/c) – (2*3)/b In diesem Fall sind die Ausdrücke zwar mathematisch äquivalent, es handelt sich jedoch um unterschiedliche Ausdrücke. Dies kann bei der Berechnung durch ein Computerprogramm auch zu unterschiedlichen Ergebnissen führen, da die Reihenfolge der Auswertung unterschiedlich ist: Falls mit Fließkomma-Arithmetik gearbeitet wird (Approximation der reellen Zahlen), sind die Ergebnisse durch Rundungsfehler fehlerbehaftet. Bei unterschiedlicher Reihenfolge der Auswertung kann es zu unterschiedlichen Rundungsfehlern kommen und damit zu unterschiedlichen Ergebnissen zweier mathematisch äquivalenten Ausdrücke. - / + b b * / a c 2 3