Prof. aa Dr. J. Giesl Programmierung WS16/17 F. Frohn, J. Hensel, D. Korzeniewski Tutoraufgabe 1 (Zweierkomplement): a) Sei x eine ganze Zahl. Wie unterscheiden sich die Zweierkomplement-Darstellungen von x und x? b) Erklären Sie im Detail, wie die beiden Ausgaben des folgenden Programms berechnet werden. public class Test { public static void main ( String [] args ) { int zahl = - 2147483648; System. out. println ( zahl + 1); System. out. println ( zahl - 1); Hinweis: 2 31 = 2147483648 c) Welche Zahlen repräsentieren die folgenden Bitfolgen im 5-Bit Zweierkomplement? 00010 10111 11011 01101 10000 a) Ausgehend von der Zweierkomplement-Darstellung von x erreicht man durch die folgenden beiden Schritte die Zweierkomplement-Darstellung von x: a) vertausche alle 0en und 1en b) addiere 1 Mit diesen beiden Schritten ist auch die Rückrichtung ( x zu x) möglich. In der folgenden Tabelle nden Sie alle Binärzahlen mit drei Ziern. Man erkennt das Muster, nach dem das genannte Verfahren funktioniert. 3 011 2 010 1 001 0 000-1 111-2 110-3 101-4 100 b) Im Folgenden werden Binärzahlen mit einem Z markiert, wenn die Zahl im Zweierkomplement verstanden werden muss. Die Zahl 1111 Z ist also als 1 zu verstehen, während 1111 für die Zahl 15 steht. Der Datentyp int benutzt 32 Bit. Die Darstellung der Zahl 2147483648 im Zweierkomplement ist: 10000000000000000000000000000000 Z (31 Nullen) Das Ergebnis der Addition zahl + 1 berechnet sich wie folgt: 10000000000000000000000000000000 Z 00000000000000000000000000000001 Z -------------------------------- 10000000000000000000000000000001 Z 1
Auch hier gibt die führende 1 an, dass die dargestellte Zahl negativ ist. Den Dezimalwert der dargestellten Zahl erhält man durch Invertieren und Addieren von 1: 01111111111111111111111111111110 00000000000000000000000000000001 -------------------------------- 01111111111111111111111111111111 Dies steht für 2147483647. Mit der Vorzeicheninformation von oben ergibt sich -2147483647. Berechnet man zahl - 1, berechnet sich das Ergebnis durch die Addition mit -1. Die Zahl -1 ist im Zweierkomplement dargestellt durch: 11111111111111111111111111111111 Z Die Addition -2147483648 + (-1) ergibt demzufolge: c) 10000000000000000000000000000000 Z 11111111111111111111111111111111 Z -------------------------------- 01111111111111111111111111111111 Z Das Ergebnis ist also nicht negativ (erkennbar durch die führende 0) und entspricht der Dezimalzahl +2147483647. Dieses Ergebnis wird auch durch das Java-Programm ausgegeben. Bitfolge 5-Bit Zweierkomplement 00010 2 10111-9 11011-5 01101 13 10000-16 Aufgabe 2 (Zweierkomplement): a) Welche Zahlen repräsentieren die folgenden Bitfolgen im 10-Bit Zweierkomplement? (3+2 Punkte) 0100110011 1011011101 0000101111 1010000000 b) Schreiben Sie für jeden der folgenden Ausdrücke ein Java Programm, das den jeweiligen Ausdruck auswertet. Was ist das Ergebnis? Begründen Sie, wie das Ergebnis zustande kommt. i) -2147483648-2147483648 > 2147483647 + 2147483647 ii) -2147483648 + (-2147483648) > 2147483647 + 2147483647 a) Bitfolge 10-Bit Zweierkomplement 0100110011 307 1011011101-291 0000101111 47 1010000000-384 2
b) i) Der Compiler gibt den Fehler error: integer number too large aus. Der Grund ist, dass die Konstante 2147483648, die auf der linken Seite der Ungleichung das zweite Argument der Subtraktion darstellt, zu groÿ ist, um durch den Datentyp int dargestellt zu werden. ii) true 2147483648 + ( 2147483648) = 100... 00 Z + 100... 00 Z = 000... 00 Z = 0 2147483647 + 2147483647 = 011... 11 Z + 011... 11 Z = 111... 10 Z = 2 Tutoraufgabe 3 (Casting): Bestimmen Sie den Typ und das Ergebnis der folgenden Java-Ausdrücke und begründen Sie Ihre Antwort. Sollte der Ausdruck nicht typkorrekt sein, begründen Sie, worin der Fehler besteht. Dabei seien die Variablen x, y und z wie folgt deklariert: int x = 1; int y = 2; int z = 3; a) false && true b) 10 / 3 c) 10 / 3. d) x == y? x > y : y < z e) (byte) (127 + 1) f) 'x' + y + z g) x + y + "z" h) 1 0 3
int x = 1; int y = 2; int z = 3; a) false && true Der Ausdruck liefert den Wert false vom Typ boolean, da die logische Und-Verknüpfung zweier boolean Werte hier ganz normal ausgeführt werden kann. b) 10 / 3 Der Ausdruck liefert den int-wert 3, da bei der Division zweier int-werte in Java Ganzzahldivision ohne Rest verwendet wird. c) 10 / 3. Der Ausdruck liefert den double-wert 3.3333333333333335, da der int-wert 10 für die double-division erst zu double konvertiert wird. d) x == y? x > y : y < z Der Ausdruck liefert den boolean-wert true, da zuerst der boolean-vergleich x == y zu false und anschlieÿend y < z zu true ausgewertet wird. Der Typ von x > y ist ebenfalls boolean, weshalb kein Fehler auftritt. e) (byte) (127 + 1) Der Ausdruck liefert das Ergebnis -128, da zuerst die int-addition durchgeführt wird und das Ergebnis +128 anschlieÿend in den byte-datentypen konvertiert wird. Dieser Datentyp kann diesen Wert allerdings nicht darstellen. Daher werden nur die letzten 8 Bit berücksichtigt (alle zusätzlichen Bits werden also abgeschnitten; dies wird auch Overow oder auf Deutsch Überlauf genannt). f) 'x' + y + z Durch die Auswertung von links nach rechts wird zuerst 'x' + y ausgewertet. Dafür wird das Zeichen 'x' zuerst in die int-zahl 120 konvertiert. Dies ergibt also 120 + 2 = 122. Dieser Wert wird dann mit der int-zahl 3 addiert, und somit wird der Gesamtausdruck zu 125 vom Typ int ausgewertet. g) x + y + "z" Durch die Auswertung von links nach rechts wird zuerst x + y zur int-zahl 3 ausgewertet. Dieser Wert wird dann mit dem String "z" verkettet, und somit wird der Gesamtausdruck zu "3z" vom Typ String ausgewertet. h) 1 0 Der Ausdruck liefert einen Fehler, da 1 und 0 vom Typ int sind und damit der boolean-vergleich nicht möglich ist. Aufgabe 4 (Casting): (8.5 Punkte) Bestimmen Sie den Typ und das Ergebnis der folgenden Java-Ausdrücke. Begründen Sie Ihre Antwort und geben Sie dabei für alle auftretenden Typkonvertierungen den resultierenden Typ und den resultierenden Wert an. Geben Sie darüber hinaus an, ob es sich um explizite oder implizite Konvertierungen handelt. Sollte der Ausdruck nicht typkorrekt sein, begründen Sie, worin der Fehler besteht. Dabei seien die Variablen x und y wie folgt deklariert: int x = 120; int y = 2; a) '4' + '7' b) (int) ((char) 65536) c) (x < y) < true d) (long)3f/3.1 == (int)3/3.2d 4
e) (long)(3f/3.1) == (int)(3/3.2d) f) 1L + (float) 3D int x = 120; int y = 2; a) '4' + '7' Der Ausdruck liefert 107 vom Typ int. Beide char-werte werden zunächst implizit zu int-werten konvertiert (52 bzw. 55). Die anschlieÿende Addition ergibt 107. b) (int) ((char) 65536) Der Ausdruck liefert den Wert 0 vom Typ int. Bei der expliziten Konvertierung von 65536 zum Typ char tritt ein Überlauf auf, sodass das Ergebnis von (char) 65536 der Wert (char) 0 ist. Anschlieÿend wird der Wert (char) 0 explizit zum Wert 0 vom Typ int konvertiert. c) (x < y) < true Der Ausdruck liefert einen Compiler-Fehler. Der Ausdruck x < y würde zu false auswerten und hat somit den Typ boolean. Da der Operator < in Java für den Typ boolean nicht deniert ist, ist der Ausdruck nicht typkorrekt. d) ((long)3f/3.1) == ((int)3/3.2d) Der Ausdruck liefert false vom Typ boolean. Auf der linken Seite wird der Dividend explizit zum Wert 3 vom Typ long konvertiert. Anschlieÿend wird der Dividend implizit zum Wert 3.0 vom Typ double konvertiert, damit die Division durchgeführt werden kann. Somit liefert die Division auf der linken Seite den Wert 0.9677419354838709 vom Typ double. Auf der rechten Seite wird der Dividend explizit zum Wert 3 vom Typ int konvertiert. Anschlieÿend wird der Dividend implizit zum Typ 3.0 vom Typ double konvertiert, damit die Division durchgeführt werden kann. Somit liefert die Division auf der rechten Seite den Wert 0.9375 vom Typ double. e) ((long)(3f/3.1)) == ((int)(3/3.2d)) Der Ausdruck liefert true vom Typ boolean. Auf der linken Seite wird der Dividend implizit zum Wert 3.0 vom Typ double konvertiert, damit die Division durchgeführt werden kann. Die Division auf der linken Seite liefert 0.9677419354838709 vom Typ double. Die anschlieÿende explizite Konvertierung zum Typ long liefert den Wert 0 vom Typ long. Auf der rechten Seite wird der Dividend implizit zum Wert 3.0 vom Typ double konvertiert, damit die Division durchgeführt werden kann. Die Division auf der rechten Seite liefert 0.9375 vom Typ double. Die anschlieÿende explizite Konvertierung zum Typ int liefert den Wert 0 vom Typ int. Um anschlieÿend den Vergleich ausführen zu können, wird die rechte Seite implizit zum Wert 0 vom Typ long konvertiert. f) 1L + (float) 3D Der Ausdruck liefert 4.0 vom Typ float. Der zweite Operand ist vom Typ float, da der Wert 3.0 vom Typ double explizit zu dem Wert 3.0 vom Typ float konvertiert wird. Folglich wird der erste Operand 1L implizit in den Wert 1.0 vom Typ float konvertiert. Anschlieÿend wird eine float-addition durchgeführt. Tutoraufgabe 5 (Programmierung): Schreiben Sie ein einfaches Java-Programm, welches den Benutzer auordert, eine positive ganze Zahl (d. h. gröÿer als 0) einzugeben. Danach soll das Programm eine durch die Return/Enter-Taste beendete Zahl einlesen. Diese Eingabeauorderung mit anschlieÿendem Einlesen soll solange wiederholt werden, bis der Benutzer eine positive Zahl eingibt. Wenn die Benutzereingabe keine Zahl ist, darf sich das Programm beliebig verhalten. Anschlieÿend soll der Benutzer aufgefordert werden, ein Wort einzugeben. Dieses soll ebenfalls durch die Return/Enter-Taste beendet werden. Das Wort soll eingelesen und schlieÿlich so oft hintereinander in einer Zeile ausgeben werden, wie durch die eingegebene positive Zahl festgelegt wurde. Hinweise: 5
Verwenden Sie die Methode next() der Klasse Scanner zum Einlesen von Strings. 6
import java. util. Scanner ; /* * * Programm zum Einlesen einer positiven Zahl und eines Worts, welches das Wort * anschliessend so oft ausgibt, wie durch die Zahl festgelegt wurde. */ public class Multiecho { public static void main ( String [] args ) { Scanner scanner = new Scanner ( System. in ); // Einlesen der Zahl mit Ueberpruefung, dass die Zahl positiv ist : int zahl = 0; while ( zahl < 1) { System. out. println (" Bitte geben Sie eine positive Zahl ein :" ); zahl = scanner. nextint (); // Einlesen des Wortes : System. out. println (" Bitte geben Sie ein Wort ein :" ); String wort = scanner. next (); // Ausgabe des Wortes so oft wie durch die Zahl festgelegt wurde : int i = 0; while (i < zahl ) { System. out. print ( wort ); i ++; Aufgabe 6 (Programmierung): (6 Punkte) Implementieren Sie eine einfache Passwortverwaltung in Java. Die Passwortverwaltung kann nur ein Passwort speichern. Die Kommunikation zwischen dem Benutzer und der Passwortverwaltung erfolgt über System.out und System.in. Nutzen sie einen Scanner, um Benutzereingaben über System.in einzulesen. Die Passwortverwaltung unterstützt die folgenden Aktionen, wobei die unterstrichenen Buchstaben den Zeichen entsprechen, die der Benutzer eingeben muss, um die jeweilige Aktion auszuwählen. Anzeigen des Passworts Setzen des Passworts Verlassen des Programms Anzeigen des Passworts die Passwortverwaltung Wenn der Benutzer A eingibt und seine Eingabe mit Enter bestätigt, dann soll den Benutzer darauf hinweisen, dass noch kein Passwort gesetzt wurde, falls die Aktion Setzen des Passworts noch nicht erfolgreich abgeschlossen wurde oder das Passwort andernfalls auf System.out ausgeben. Setzen des Passworts Wenn der Benutzer S eingibt und seine Eingabe mit Enter bestätigt, dann soll die Passwortverwaltung den Benutzer auordern, das neue Passwort einzugeben. Anschlieÿend soll der Benutzer aufgefordert werden, das neue Passwort zur Bestätigung erneut einzugeben. Falls der Benutzer zweimal das 7
gleiche Passwort eingegeben hat, soll das neue Passwort gespeichert und der Benutzer darüber informiert werden, dass das Passwort erfolgreich geändert wurde. Andernfalls soll das Passwort nicht geändert und der Benutzer darauf hingewiesen werden, dass die Bestätigung des Passworts fehlgeschlagen ist und das Passwort folglich nicht geändert wurde. Verlassen des Programms Wenn der Benutzer V eingibt und seine Engabe mit Enter bestätigt, dann soll sich die Passwortverwaltung beenden. Andere Eingaben Falls die Eingabe des Benutzers zu keinem der genannten Fälle passt, soll die Passwortverwaltung den Benutzer darauf hinweisen, dass die von ihm gewählte Aktion unbekannt ist. Beispiel Die Interaktion mit der Passwortverwaltung kann also z.b. wie folgt aussehen: W ä hlen Sie eine Aktion : Passwort * A * nzeigen Passwort * S * etzen Programm * V * erlassen > A Es wurde noch kein Passwort gesetzt! > S Neues Passwort eingeben : > test Neues Passwort best ä tigen : > tset Best ä tigung des neuen Passworts fehlgeschlagen. Passwort wurde nicht ge ä ndert. > A Es wurde noch kein Passwort gesetzt! > S Neues Passwort eingeben : > test Neues Passwort best ä tigen : > test Passwort erfolgreich ge ä ndert! > A test > test Unbekannte Aktion : test > S Neues Passwort eingeben : > abc Neues Passwort best ä tigen : > abc Passwort erfolgreich ge ä ndert! > A abc > V Auf Wiedersehen! Hinweise: Um zwei Strings str1 und str2 auf Gleichheit zu testen, verwenden Sie str1.equals(str2). 8
import java. util. Scanner ; public class Pass { public static void main ( String [] args ) { System. out. println ("Wä hlen Sie eine Aktion :" ); System. out. println (" Passwort *A* nzeigen " ); System. out. println (" Passwort *S* etzen " ); System. out. println (" Programm *V* erlassen " ); Scanner scanner = new Scanner ( System. in ); boolean passset = false ; String pass = ""; String cmd ; do { cmd = scanner. next (); if ( cmd. equals ("A" )) { if ( passset ) { System. out. println ( pass ); else { System. out. println (" Es wurde noch kein Passwort gesetzt!" ); else if ( cmd. equals ("S" )) { System. out. println (" Neues Passwort eingeben :" ); String tmp = scanner. next (); System. out. println (" Neues Passwort best ä tigen :" ); if ( tmp. equals ( scanner. next ())) { pass = tmp ; passset = true ; System. out. println (" Passwort erfolgreich ge ä ndert!" ); else { System. out. println (" Best ä tigung des neuen Passworts fehlgeschlagen." ); System. out. println (" Passwort wurde nicht ge ä ndert." ); else if (! cmd. equals ("V" )) { System. out. println (" Unbekannte Aktion : " + cmd ); while (! cmd. equals ("V" )); System. out. println (" Auf Wiedersehen!" ); Aufgabe 7 (Deck 1): Lösen Sie die Räume von Deck 1 des Spiels Codescape. (Codescape) 9