## Binärzahlen mit Python Das Dossier enthält mehrere Programmieraufgaben, um Binärzahlen mit Python-Code zu manipulieren. Hier findest du Übungen, Hinweise und Ideen, wie die Umsetzung der Algorithmen in Python gelingen könnte. ### Schleifen Bei der *direkten* Schleife ist der Ausdruck hinter `in` die Sequenz der uns interessierenden Elemente (z.B. ein String mit den Binär-Nennwerten `0` oder `1`). Die Schleifenvariable (der Name zwischen `for` und `in`) wird in jedem Schleifendurchgang auf das nächste Element gesetzt. *Direkte* Schleife über alle Buchstaben eines Strings (einer Zeichenfolge): b = '100110' for digit in b: print(digit) #### Parallel über zwei Strings Bei der _indirekten_ Schleife steht der Ausdruck hinter `in` für die Liste der Indices, ist also eine Ganzzahl (`int`). Die Schleifenvariable heisst meistens `index` oder kurz `i`. Um auf das uns interessierende Element zuzugreifen, müssen wir einen Listenzugriff programmieren, z.B. `liste[index]`. Mit dem Index kann auch gerechnet werden, um zum Beispiel jedes zweite Element oder die Elemente in umgekehrter Richtung zu erhalten. *Indirekte* Schleife über die Buchstaben in zwei gleichlangen Strings: b1 = '10011010' b2 = '11110000' for index in range(len(b1)): digit1 = b1[index] digit2 = b2[index] print(digit1, digit2) Oder mit `while`: b1 = '10011010' b2 = '11110000' index = 0 while index < len(b1): digit1 = b1[index] digit2 = b2[index] print(digit1, digit2) index = index + 1 Elegante Alternative mit [[https://docs.python.org/2.7/library/functions.html#zip|zip]] (nicht Prüfungsstoff): _Zip_ ist das englische Wort für Reissverschluss, wir nehmen also abwechslungsweise von jedem Argument ein Element... 🤐 b1 = '10011010' b2 = '11110000' for digit1, digit2 in zip(b1, b2): print(digit1, digit2) #### Rückwärts Erste Möglichkeit: Indirekte Schleife mit Umrechnung des Index: b = '111000' for index in range(len(b)): reversed_index = len(b) - 1 - index digit = b[reversed_index] print(digit) Etwas kompakter: `range` mit einem Step-Argument: b = '111000' # range(start, stop, step): Start with len - 1, stop at 0 (so before -1), increment is -1 for index in range(len(b) - 1, -1, -1): digit = b[index] print(digit) Oder mit `while`: b = '111000' index = len(b) - 1 # Letzter gültiger Index while index >= 0: digit = b[index] print(digit) index = index - 1 Noch kompakter: Die Funktion [[https://docs.python.org/2.7/library/functions.html#reversed|reversed]] (kein Prüfungsstoff) kehrt jede Sequenz (Liste, String) um: b = '111000' for d in reversed(b): print(d) Noch kompakter (aber auch leserlich?), die Verwendung von [[https://stackoverflow.com/questions/509211/how-slicing-in-python-works/509295#509295|String Slicing]] (kein Prüfungsstoff): b = '111000' for d in b[::-1]: print(d) #### Rückwärts über zwei Strings? ++++Lösung| Am einfachsten mit `while`: b1 = '111000' b2 = '101010' index = len(b1) - 1 while index >= 0: digit1 = b1[index] digit2 = b2[index] print(digit1, digit2) index = index - 1 Eleganter mit `reversed` und `zip` (kein Prüfungsstoff): b1 = '111000' b2 = '101010' for d1, d2 in zip(reversed(b1), reversed(b2)): print(d1, d2) ++++ ### Division und Rest Zwei Zahlen `a` und `b` - was gibt $\lfloor a/b\rfloor$ (Ganzzahldivision), und wieviel ist der Rest der Division? a = 42 b = 2 quotient = a // b rest = a % b ### Strings und Integers Jeder Ausdruck in Python hat einen Type. Der Type bestimmt, welche Operationen damit ausgeführt werden können: Mit Zahlen können wir rechnen, mit Zeichenketten nicht. Alle Types können auch als Zeichenkette (String) dargestellt werden, und aus einem String wieder zurückverwandelt werden. #### Zeichenketten (Strings) Ein `string` ist eine Folge von Buchstaben. Die Folge kann auch leer sein (`''`). Strings sind *immutable*, können also nicht verändert werden. Alle anderen Types müssen sich als String darstellen lassen, indem die Funktion `str()` aufgerufen wird. Strings unterstützen den `+` Operator, um zwei Strings zu verketten. Dies kann verwirrend sein, wenn die Absicht ist, Zahlen zu addieren und stattdessen Strings verkettet werden: digit1 = '1' digit2 = '1' summe = digit1 + digit2 # Absicht: Summe soll die Zahl 2 sein print(summe) # Resultat: String-Verkettung zu '11' print(int(digit1) + int(digit2)) # Abhilfe: Strings in Zahlen konvertieren #### Zahlen Zahlen können entweder Ganzahlen (`int` - Integer) oder Fliesskommazahlen (`float` - Floating Point Number) sein. Strings können in Zahlen umgewandelt werden, wenn der Inhalt des Strings einer Zahl entspricht: zahl = int('42') # OK zahl = int('3.14') # FEHLER! zahl = float('3.14') # OK zahl = float('foobar') # FEHLER! Addieren, subtrahieren oder multiplizieren wir zwei Ganzzahlen, resultiert wiederum eine Ganzzahl. Bei der Division hingegen entsteht als Resultat ein `float`. ### Strings verketten Strings sind *immutable*, anders als bei Listen können wir nicht einfach einen Buchstaben ersetzen in einem String. Aber wir können mit dem `+` Operator zwei Strings verketten, um einen neuen String zu erhalten: s1 = 'foo' s2 = 'bar' print(s1 + s2) # prints 'foobar' Dasselbe ist auch praktisch, um Buchstaben in einer Schleife aneinanderzureihen: def flip_bits(b): result = '' # start with empty string for digit in b: if digit = '1': # if digit is a one... result = result + '0' # ...append a zero elif digit = '0': result = result + '1' # otherwise append a one return result **Achtung**: Der `+` Operator für Strings funktioniert nur, wenn beide Operanden Strings sind - falls eine Seite eine Zahl ist, führt das zum Programmabbruch: a = 101 # eine Zahl b = '010' # ein String c = a + b # Fehler! # Zahl umwandeln in String c = str(a) + b # OK: + bedeutet String-Verkettung, c ist der String '101010' # String umwandeln in Zahl c = a + int(b) # OK: + bedeutet Ganzzahl-Addition, c ist die Ganzzahl (int) 111 **String mit Nullen auffüllen** Ziel: einen Binärstring vorne mit Nullen auffüllen, damit mindestens `n` Stellen vorhanden sind: Variante 1: Mit `while`: b = '1010' n = 8 while len(b) < n: b = '0' + b Variante 2 (nicht Lernstoff): Strings multiplizieren Strings können übrigens auch mit dem `*` Operator verknüpft werden - zum Beispiel um die Anzahl fehlender Nullen zu erstellen: b = '1010' n = 8 count = n - len(b) # count = 8 - 4 = 4 zeros = '0' * count # zeros = '0000' b = zeros + b Variante 3 (nicht Lernstoff): Eleganter mit [[https://docs.python.org/2.7/library/stdtypes.html?highlight=zfill#str.zfill|zfill]]: b = '1010' n = 8 b = b.zfill(n) ### Funktionen #### Checkliste * `return` ist vorhanden? * `return` ist an der richtigen Stelle / Einrückung? * Alle Berechnungsgrundlagen werden als Argumente übergeben?