Dr. Ekkart Kindler FG Softwaretechnik Institut für Informatik Technische Informatik für Ingenieure Winter 2006/2007 – Übungsblatt Nr. 1 4. Dezember 2006 Übungsgruppenleiter: K. Hojenski M. Meyer E. Münch S. Pook A. Znamenshchykov D. Travkin Seite 1(4) Aufgabe 2: (Der erste Algorithmus) In der Vorlesung wurde ein Algorithmus für die Addition zweier positiver Zahlen vorgeführt (siehe Vorlesungsunterlagen). Formulieren Sie diesen Algorithmus möglichst präzise in natürlicher Sprache. Hinweis: Die Lösung der Aufgabe könnte wie folgt beginnen: 1. Schreibe die erste der beiden zu addierenden Zahlen - mit den höherwertigen Ziffern beginnend - von Links nach Rechts waagerecht in eine Zeile. 2. Schreibe darunter die zweite ... Lösungsvorschlag: 1. Gegeben sind zwei zu addierende Zahlen, wobei die größere durch die Ziffernfolge xm xm-1 … x0 und die kleinere durch die Ziffernfolge yn yn-1 … y0 dargestellt wird. 2. Schreibe zunächst die größere Zahl waagerecht als Ziffernfolge xm xm-1 … x0. Schreibe dann die kleinere Zahl waagerecht als Ziffernfolge yn yn-1 … y0 unter die größere Zahl, so dass Ziffern yi unter Ziffern xi mit gleichem Index i stehen: xm xm-1 yn … yn-1 … xk yk xk-1 yk-1 … … x1 y1 x0 y0 3. Schreibe darunter den Übertrag, der als Ziffernfolge uh uh-1 … u0 dargestellt wird: Die Ziffern des Übertrags werden waagerecht unter die Ziffernfolge yn yn-1 … y0 geschrieben, so dass Ziffern ui wiederum unter Ziffern yi mit gleichem Index i stehen. Die Ziffer u0 des Übertrags ist per Definition immer 0. Der größte Index h der Ziffernfolge uh uh-1 … u0 ist genau um 1 größer als der größte Index m der Ziffernfolge xm xm-1 … x0: h = m+1. 4. Notiere das Ergebnis als Ziffernfolge zj zj-1 … z0 analog zum Übertrag unter die Ziffernfolge uh uh-1 … u0: Ziffern ui des Übertrags und Ziffern des Ergebnisses zi mit gleichem Index i stehen untereinander. Werden wie in dieser Aufgabe genau zwei Zahlen addiert, dann haben die Ziffernfolgen uh uh-1 … u0 und zj zj-1 … z0 die gleiche Anzahl an Ziffern und für die größten Indizes h und j gilt: h = j. xm uh uh-1 zj zj-1 5. xm-1 yn … … … yn-1 … xk yk uk zk xk-1 yk-1 uk-1 zk-1 … … … … x1 y1 u1 z1 x0 y0 0 z0 Addiere mit dem kleinsten Index i = 0 beginnend von rechts nach links fortschreitend die Ziffern xi und yi: Beginne mit der Addition von x0 und y0. Das Ergebnis hat höchstens zwei Stellen: e1 e0. Technische Informatik für Ingenieure – Übungsblatt 1 Seite 2(4) Schreibe die erste, kleinere Stelle e0 als Ergebnis z0. Notiere die zweite Stelle e1 als Übertrag u1. Falls das Ergebnis nur eine Stelle e0 benötigt, ist der Übertrag u1 = 0. Fahre fort mit der Addition von x1, y1 und dem Übertrag u1. Das Ergebnis hat wiederum höchstens zwei Stellen e1 und e0. Notiere e0 als Ergebnis z1 und e1 als Übertrag u2. Falls das Ergebnis nur eine Stelle e0 benötigt, ist der Übertrag u2 = 0. Fahre fort mit der Addition von xi, yi und dem Übertrag ui. Falls der Index i größer ist als der größte Index n der Ziffernfolge yn yn-1 … y0, addiere lediglich xi und ui. Wiederum hat das Ergebnis höchstens zwei Stellen e1 und e0. Notiere e0 als Ergebnis zi und e1 als Übertrag ui+1. Falls das Ergebnis nur eine Stelle e0 benötigt, ist der Übertrag ui+1 = 0. Wiederhole diesen Schritt mit aufsteigendem Index i, solange der Index i kleiner oder gleich dem größten Index m der Ziffernfolge xm xm-1 … x0 ist. Nach Abarbeitung der Ziffernfolge xm xm-1 … x0 übertrage den Übertrag uh als Ziffer zj des Ergebnisses zj zj-1 … z0. Aufgabe 4 d): (Das erste Java-Programm) Protokollieren Sie das Verhalten des Programms bei der Eingabe von sehr großen und sehr kleinen Zahlen. Was passiert, wenn negative Zahlen eingegeben werden? Wann wird das Ergebnis „0“? Wann wird das Ergebnis falsch? Eingabe sehr großer Zahlen: Bis zur Eingabe der Zahl 12 gibt das Programm ein korrektes Ergebnis aus: Geben Sie eine natuerliche Zahl ein: 12 Das Ergebnis ist 479001600. Die Eingabe der Zahl 13 führt zum ersten falschen Ergebnis: Geben Sie eine natuerliche Zahl ein: 13 Das Ergebnis ist 1932053504. (Richtig wäre das Ergebnis 13! = 6227020800). Erklärung: Bei Java werden ganzzahlige Werte mit dem Datentyp Integer gespeichert. Zur Speicherung einer Integer-Zahl stehen bei Java 32 Bit zur Verfügung. Von diesen 32 Bit wird ein Bit zur Speicherung des Vorzeichens benötigt, so dass zur Darstellung der Zahl effektiv 31 Bit zur Verfügung stehen. Zusätzlich muss die 0 dargestellt werden. Daher ist die größte darstellbare positive Zahl um genau 1 kleiner als die größte darstellbare negative Zahl: Größte darstellbare positive Zahl: Größte darstellbare negative Zahl: 231-1 = 2147483647 231 = -2147483648 Bei Java können die größte positive und die größte negative Zahl mit Integer.MAX_VALUE und Integer.MIN_VALUE ermittelt werden: Integer.MAX_VALUE: 2147483647 Integer.MIN_VALUE: -2147483648 Werden diese Werte über- oder unterschritten, dann tritt ein Überlauf auf: Die Zahl kann nicht mehr vollständig dargestellt werden, nur die letzten 31 Bit werden korrekt gespeichert. Die höheren Bit gehen verloren. Das Vorzeichen-Bit wird durch Bit 32 der zu speichernden Zahl ersetzt. Dieser Effekt kann bei Eingabe der Zahl 17 beobachtet werden: Geben Sie eine natuerliche Zahl ein: 17 Das Ergebnis ist -288522240. Technische Informatik für Ingenieure – Übungsblatt 1 Seite 3(4) Ausgabe der „0“ als Ergebnis Die Eingabe einer Zahl größer gleich 34 führt zum Ergebnis „0“: Geben Sie eine natuerliche Zahl ein: 34 Das Ergebnis ist 0. Erklärung: Der oben beschriebene Effekt lässt sich durch die interne Darstellung von Integer-Zahlen durch Java erklären: Eine 32 Bit große Integer-Zahl ist eine 32-stellige Folge binärer Ziffern. Um positive und negative Zahlen darstellen zu können, verwendet Java das Zweierkomplement: Integer.MAX_VALUE = 2147483647 = 0111…111 Integer.MIN_VALUE = -2147483648 = 1000…000 Das höchstwertige Bit (Bit mit Index 32) legt dabei das Vorzeichen fest: „0“ für eine positive Zahl, „1“ für eine negative Zahl. Die Dezimalzahl „0“ wird repräsentiert durch: 0 = 0000…000. Bei der Berechnung der Fakultät für die Zahl n werden n Multiplikationen durchgeführt. Dabei wird das Zwischenergebnis im ständigen Wechsel mit einer geraden und einer ungeraden Zahl multipliziert. Durch die Multiplikation mit geraden Zahlen werden die Binärziffern vom Index 0 beginnend mit steigendem Index nacheinander zu „0“. Bei der Berechnung der Fakultät sind nach 32 Schleifendurchläufen die ersten 31 Stellen mit „0“ belegt und das Vorzeichen (Bit 32) auf „1“ gesetzt: Die größte darstellbare negative Zahl ist erreicht. Findet nun eine Multiplikation mit einer ungeraden Zahl statt (was bei der letzten Multiplikation zur Berechnung von 33! Der Fall ist), dann ändert sich an der Belegung im Speicher nichts. Wird die größte darstellbare negative Zahl hingegen mit einer geraden Zahl multipliziert, dann wird Bit 32 zu „0“. Da die restlichen Speicherzellen bereits mit „0“ belegt sind, entspricht diese Belegung genau der Darstellung der Dezimalzahl „0“. Das folgende Programm verdeutlicht diese Effekte: public class Ueberlauf { public static void main(String[] args) { int i = Integer.MAX_VALUE; Out.println("Integer.MAX_VALUE: " + i); i += 1; Out.println("Integer.MAX_VALUE + 1: " + i); i = Integer.MAX_VALUE; i *= 3; Out.println("Integer.MAX_VALUE * 3: " + i); i = Integer.MAX_VALUE; i *= 2; Out.println("Integer.MAX_VALUE * 2: " + i); Out.println(); i = Integer.MIN_VALUE; Out.println("Integer.MIN_VALUE: " + i); i -= 1; Out.println("Integer.MIN_VALUE - 1: " + i); i = Integer.MIN_VALUE; i *= 3; Out.println("Integer.MIN_VALUE * 3: " + i); Technische Informatik für Ingenieure – Übungsblatt 1 Seite 4(4) i = Integer.MIN_VALUE; i *= 2; Out.println("Integer.MIN_VALUE * 2: " + i); } } Ausgabe des Programms: Integer.MAX_VALUE: 2147483647 Integer.MAX_VALUE + 1: -2147483648 Integer.MAX_VALUE * 3: 2147483645 Integer.MAX_VALUE * 2: -2 Integer.MIN_VALUE: -2147483648 Integer.MIN_VALUE - 1: 2147483647 Integer.MIN_VALUE * 3: -2147483648 Integer.MIN_VALUE * 2: 0 Eingabe der Zahl 0: Für die Eingabe der Zahl 0 gibt das Programm das Ergebnis 1 aus, was nach Definition der Fakultät richtig ist: Geben Sie eine natuerliche Zahl ein: 0 Das Ergebnis ist 1. Erklärung: Die Bedingung der Schleife wird für n = 0 nicht erfüllt. Daher wird die Schleife in diesem Fall nicht durchlaufen und der Initialisierungswert von Erg ausgeben. Der Initialisierungswert von Erg ist im Programm auf 1 gesetzt. Eingabe negativer Zahlen: Für die Eingabe negativer Zahlen gibt das Programm das Ergebnis 1 aus. Fakultäten sind nur für natürliche Zahlen und 0 definiert. Daher ist dieses Ergebnis streng genommen falsch. Richtig wäre z.B. die Ausgabe: Geben Sie eine natuerliche Zahl ein: -1 Fakultäten für negative Zahlen sind nicht definiert. Diese Ausgabe ließe sich durch Erweiterung des Programms um eine Bedingung erzeugen: Out.print("Geben Sie eine natuerliche Zahl ein: "); int n = In.readInt(); // weitere Initialisierungen if (n >= 0) { // Berechnung der Fakultät hier einfügen Out.println("Das Ergebnis ist " + erg + "."); } else { Out.println("Fakultäten für negative Zahlen sind nicht definiert."); }