Institut für Informatik Universität Osnabrück, 08.11.2016 Prof. Dr. Oliver Vornberger http://www-lehre.inf.uos.de/~ainf Lukas Kalbertodt, B.Sc. Testat bis 16.11.2016, 14:00 Uhr Nils Haldenwang, M.Sc. Übungen zu Algorithmen Wintersemester 2016/2017 Blatt 3: Darstellung und Operationen im Binärsystem Aufgabe 3.1: Fragen (30 Punkte) Beantworten Sie Ihrer Tutorin beziehungsweise Ihrem Tutor Fragen zu den Inhalten der Veranstaltung. Aufgabe 3.2: Primzahltest (25 Punkte) Implementieren Sie eine Klasse Primzahltest.java, welche eine positive, ganze Zahl n einliest und auf naive Art testet, ob diese eine Primzahl ist. Prüfen Sie dazu, ob n durch eine der Zahlen zwischen 2 und n 1 teilbar ist. Überlegen Sie, wie sie die Laufzeit ihres Programms optimieren können und setzen Sie die entsprechenden Ideen um. /****************************** Primzahltest.java *************************/ import AlgoTools.IO; /** * Liest eine natuerliche Zahl ein und testet, ob diese * eine Primzahl ist. */ class Primzahltest { public static void main(string[] args){ int n; do { n = IO.readInt("Bitte eine ganze Zahl > 1: "); while(n <= 1); boolean istprim = true; for(int i = 2; i < n; i++){ if(n % i == 0){ istprim = false;
if(istprim){ IO.println(n + " ist eine Primzahl."); else { IO.println(n + " ist keine Primzahl."); /****************************** PrimzahltestOptimiert.java ********************* import AlgoTools.IO; /** * Liest eine natuerliche Zahl ein und testet, ob diese * eine Primzahl ist. */ class PrimzahltestOptimiert { public static void main(string[] args){ int n; do { n = IO.readInt("Bitte eine ganze Zahl > 1: "); while(n <= 1); boolean istprim = true; // Hier die zwei schon testen, damit man danach nur // noch ungerade testen muss, da alle geraden // Zahlen vielfache von zwei sind und damit // keine Primzahl mehr sein koennen. if(n == 2){ istprim = true; else if(n % 2 == 0){ istprim = false; else { // Ganzzahlige Wurzel berechnen // sqrt(x) < y <=> x < y*y int wurzel = n; while(n < wurzel*wurzel){ wurzel--; 2
// Es genuegt hier nur die ungeraden Zahlen zu testen (s.o.) // Ausserdem reicht es bis zur Wurzel zu testen, da ein Produkt // von Zahlen groesser der Wurzel auch groesser als die urspruengliche // Zahl waere. for(int i = 3; i <= wurzel && istprim; i = i+2){ if(n % i == 0){ istprim = false; if(istprim){ IO.println(n + " ist eine Primzahl."); else { IO.println(n + " ist keine Primzahl."); Aufgabe 3.3: Zweierkomplement (10 Punkte) Lösen Sie die folgenden theoretischen Aufgaben schriftlich. Überführen Sie die folgenden Zahlen in die 8-Bit Zweier-Komplement-Darstellung. Führen Sie die arithmetische Operation im Zweier-Komplement durch und wandeln Sie das Ergebnis in die dezimale Darstellung um. Überprüfen Sie das Ergebnis mit dem Verfahren der Verdoppelung des führenden Bits. Schreiben Sie Ihre Berechnungen und Ergebnisse auf. a) 36 + 105 b) 10 23 c) 11 16 a) 36 + 105 000100100 36 +001101001 +105 ---------- --- =100001101 ^^ sind nicht gleich => Ergebnis: Ueberlauf, ungültiges Ergebnis b) 10-23 00010111 = 23 000001010 10 11110011-13 => 11101001 = -23 +111101001-23 => 00001101 13 3
--------- --- 111110011-13 ^^ sind gleich => Ergebnis: ok c) -11-16 00001011 = 11 111110101-11 11100101-27 => 11110101 = -11 +111110000-16 => 00011011 27 --------- --- 00010000 = 16 111100101-27 => 11110000 = -16 ^^ sind gleich => Ergebnis: ok Aufgabe 3.4: Float-Kodierung (10 Punkte) a) Geben Sie die 32-Bit Kodierung nach der Definition im Kapitel 2.4.2 des Skripts für die drei folgenden Gleitkommazahlen vom Typ float an: i) 42.23 ii) -73.73 iii) 6.4 b) Welche Zahl wird kodiert durch: 0 00000101 00101101110101110000101 a) i) 42.23 = 2^(5) * 1.3196875 0 00000101 01010001110101110000101 ii) -73.73 = -1 * 2^(6) * 1.15203125 1 00000110 00100110111010111000010 iii) 6.4 = 2^(2) * 1.6 0 00000010 10011001100110011001101 Die Zahl 6.4 kann nicht exakt dargestellt werden, da die Mantisse periodisch ist. Der Rechner rundet intern die Werte. Dieses Problem ergibt sich bei vielen Gleitkommazahlen. So z.b. auch bei 0.1 0.2 0.3 0.4 0.6 0.7 und so weiter 4
b) 0 00000101 00101101110101110000101 = 32 * (1 + (2^(-3) + 2^(-5) + 2^(-6) + 2^(-8) + 2^(-9) + 2^(-10) + 2^(-12) + 2^(-14) + 2^(-15) + 2^(-16) + 2^(-21) + 2^(-23))) = 37.73 Aufgabe 3.5: Float-Kodierung Programmieren (25 Punkte) Schreiben Sie ein Java-Programm, das nach Eingabe einer Gleitkommazahl vom Typ float die 32- Bit Darstellung (siehe Skript, Kapitel 2.4.2) ausgibt. Sie können Gleitkommazahlen, die zu einem negativen Exponenten führen würden, vernachlässigen. Es ist hinreichend, wenn ihr Programm Gleitkommazahlen mit positiven Exponenten verarbeiten kann. /****************************** Gleitkomma.java *****************************/ import AlgoTools.IO; /** * Liest eine Gleitkommazahl ein und gibt die binaere 32-Bit float-darstellung * wieder aus. * * @author Sebastian Buescher (sbuesche@uos.de) * @author Nicolas Neubauer (nineubau@uos.de) * @author Jana Lehnfeld (jlehnfel@uos.de ) */ public class Gleitkomma { public static void main(string[] args) { float eingabe; float tmp; double f; double zweihoch; int exponent = 0; int newexponent = 0; int expotmp = 0; 5
do { eingabe = IO.readFloat("Bitte eine Gleitkommazahl eingeben: "); while(eingabe > -1.0 && eingabe < 1.0); // Vorzeichenbit ausgeben und Zahl ggf. anpassen if (eingabe < 0) { IO.print("1 "); eingabe = -1 * eingabe; else { IO.print("0 "); // Exponent berechnen tmp = eingabe; // Eingabe zwischenspeichern while (eingabe >= 2) { eingabe /= 2; exponent++; eingabe = tmp; // Eingabe wieder herstellen IO.print("0"); // Vorzeichenbit des Exponenten newexponent = exponent; expotmp = newexponent; // fuer jedes Bit for (int bit = 7; bit > 0; bit--) { // laufe bis zum Beginn der Binaerzahl for (int k = 1; k < bit; k++) { newexponent /= 2; // und drucke aus if (newexponent % 2!= 0) { IO.print("1"); else { IO.print("0"); newexponent = expotmp; IO.print(" "); zweihoch = 1; 6
// zwei hoch Exponent berechnen. for (int i = 0; i < exponent; i++) { zweihoch *= 2; f = eingabe / zweihoch - 1; // Mantisse // Mantisse ausgeben, Algorithmus siehe Skript S. 25. for (int i = 0; i < 23; i++) { f = f * 2.0; if (f >= 1.0) { IO.print("1"); f = f - 1; else { IO.print("0"); IO.println(); 7