## 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?