SS 2004 Technische Universität Darmstadt FB Mathematik, AG 7, Diskrete Optimierung Prof. Dr. Alexander Martin Daniel Junglas Lars Schewe 2. Übung Computerorientierte Mathematik Abgabe der Hausübungen am 10. Mai vor der Übung Praxis P1. Quoting Besetzen Sie die Umgebungsvariable INHALT mit dem Text ,,Inhalt des Verzeichnisses: ” und führen Sie nacheinander die folgenden Befehle aus: fb04305:~ > echo $INHALT * fb04305:~ > echo "$INHALT *" fb04305:~ > echo ’$INHALT *’ Was tun diese Befehle und was ist der Unterschied zwischen einfachen, doppelten bzw. gar keinen Anführungszeichen? P2. ASCII-Tabelle Schreiben Sie ein Programm, das eine Tabelle ausgibt, in der alle Zahlen von 32 bis 255 (einschließlich) zusammen mit dem jeweiligen Buchstaben der ASCII-Tabelle dargestellt sind. Die ausgegebene Tabelle soll acht Spalten haben. P3. Eingabe von Zahlen Mit Hilfe der Funktion scanf() (siehe auch man scanf) kann wie folgt eine Zahl von der Tastatur eingelesen werden: #include <stdio.h> ... int zahl; ... printf("Eine Zahl, bitte:"); scanf("%d", &zahl); (was ,,&zahl” genau bedeutet ist dabei zunächst nicht wichtig). Nach der Ausführung dieses Codefragments ist die eingegebene Zahl in der Variablen zahl gespeichert. Schreiben Sie ein Programm, das eine Zahl einliest und für diese Zahl ausgibt, ob sie positiv oder negativ bzw. ob sie gerade oder ungerade ist. Dieser Schritt soll so lange wiederholt werden, bis 0 eingegeben wird. Hinweis: Um zu testen, ob eine Zahl gerade oder ungerade ist, kann man sich einen der beiden folgenden Operatoren zunutze machen (probieren Sie ruhig einmal beide aus): % Der %-Operator liefert den Rest einer ganzzahligen Division, d.h. 4 % 3 liefert 1. / Dies ist der Divisionsoperator. Sind beide Argumente des Operators ganzzahlig, dann wird ganzzahlige Division durchgeführt. Dies entspricht einer Division mit Rest, bei der der Rest ignoriert wird. Demnach liefert 4 / 3 den Wert 1. P4. Austausch von Ziffern Schreiben Sie ein Programm, das vom Benutzer zunächst zwei ganze Zahlen a und b verlangt. Danach soll noch eine weitere Zahl c eingelesen werden. Das Programm vertauscht dann die (dezimalen) Ziffern an der c-ten Stelle von a und b und gibt das Ergebnis auf dem Bildschirm aus. P5. Prä- und Postinkrement Betrachten Sie das folgende Programm: #include <stdio.h> int main (void) { int x = 5; printf("%d, %d\n", ++x, x--); return 0; } Was für eine Ausgabe erwarten Sie? Was wird tatsächlich ausgegeben? Hinweis: Aufgrund dieses Ergebnisses, sollte man möglichst nicht mehrere Prä- und PostinkrementOperatoren in einem Statement kombinieren, erst recht nicht für ein und dieselbe Variable. Theorie T1. Nochmal 2-Komplement Betrachten Sie den folgenden 32 Bit langen Auszug aus dem Hauptspeicher: 11000100011010000111001001100101. Welche Zahlen/Buchstaben werden definiert, wenn man ihn als (a) vier Buchstaben vom Typ unsigned char, (b) eine Zahl vom Typ unsigned long, (c) eine Zahl vom Typ long, (d) zwei Zahlen vom Typ unsigned short oder (e) zwei Zahlen vom Typ short betrachtet? (Alle Zahlen sollen als Zahlen im 2-Komplement betrachtet werden.) T2. Bitoperationen Nehmen den arithmetischen Operatoren ,,+”, ,,-” usw. gibt es auch Operatoren, mit denen man Zahlen/Variablen bitweise verknüpfen kann. Bei diesen Operationen werden die beteiligten Variablen Bit für Bit miteinander verknüpft und das Ergebnis wird ebenfalls Bit für Bit in der entsprechenden Variablen gespeichert. Die Operatoren zur Bitverknüpfung sind bitweises Und (&-Operator), bitweises Oder (|-Operator), bitweises Exklusiv-Oder (^-Operator) und bitweise Negation (~-Operator): & 0 1 0 0 0 1 0 1 | 0 1 0 0 1 1 1 1 ^ 0 1 0 0 1 1 1 0 ~ 0 0 1 1 0 Betrachten wir uns beispielsweise die Anweisung unsigned short a = 4 | 3; Die binäre Darstellung von 4 im 2-Komplement ist 100 und die von 3 ist 11 (führende Nullen sind hier weggelassen, sind aber trotzdem wichtig!). Nun wird Bit für Bit die Oder-Operation ausgeführt: Ist ein Bit in der binären Darstellung von 3 oder 4 gesetzt, dann wird das entsprechende Bit auch im Ergebnis gesetzt. Ist ein Bit in keiner der beiden Binärdarstellungen gesetzt, dann wird das Bit auch im Ergebnis nicht gesetzt. Die Anweisung oben sorgt also dafür, dass in a das Bitmuster 111 gespeichert wird. (a) Welches Bitmuster ist in a nach den folgenden Anweisungen gespeichert? (a soll vom Typ unsigned short sein) i. ii. iii. iv. a a a a = = = = 5 | 3 5 & 3 5 ^ 3 ~5 (b) Wie kann man testen ob ein bestimmtes Bit (z.B. bit5) gesetzt ist oder nicht? (c) Wie kann man testen, ob eine Variable gerade/ungerade ist? (d) Wie kann man bit5 in einer Variablen löschen/setzen? (e) Möchte man die Werte zweier Variablen x und y vertauschen, dann verfährt man normalerweise so { int z = x; x = y; y = z; } Man kann aber auch ohne z auskommen: Wie kann man die Werte zweier Variablen nur mit dem ^-Operator vertauschen, ohne eine zusätzliche Variable zu verwenden? (Dazu sind nicht mehr als drei Anweisungen nötig) Was passiert, wenn man eine Variable auf diese Art mit sich selbst vertauscht? T3. Überlauf Wieso führt das folgende Code-Fragment zu einer Endlosschleife? short i; unsigned short j = 40000; for (i = 0; i < j; i++) { printf("%d\n", i); } T4. Schleifen Grundsätzlich kann man jede for-Schleife auch als while-Schleife schreiben und ungekehrt. (a) Was berechnet das folgende Code-Fragment (x und n sind vom Typ int)? x = -1; while (n > 0 ) { n = n / 3; x++; } Schreiben Sie die while-Schleife als eine for-Schleife. (b) Schreiben Sie die Schleife for (i = 0; i < 10; i++) printf("%d, i); als while-Schleife.