====== Algorithmen II ======
===== Struktogramme und Python =====
==== Aufgaben A ====
* Folgende Aufgaben hast du ev. bereits mit [[gf_informatik:algorithmen_i#aufgaben_c|Struktogrammen gelöst]]. Studiere nochmals deine jeweiligen Lösungen und stelle sicher, dass du jeden Schritt verstehst.
* Schreibe nachher den zugehörigen Python-Code.
* Verwende keine vordefinierten Funktionen wie z.B. `max()` oder `sorted()`, programmiere alles selber.
=== Aufgabe A1: Maximum ===
* Teil 1: Zwei Zahlen sollen eingegeben und die grössere der beiden Zahlen ausgegeben werden. Die grössere von zwei gleich grossen Zahlen ist einfach diese eine Zahl.
* Teil 2: Schreibe Code um als Funktion `max2(a, b)`, die das Maximum von a und b mit `return` _zurückgibt_. Die _Eingabe_ (`input`) und die _Ausgabe_ (`print`) sollen ausserhalb der Funktion erfolgen.
* Teil 3: Schreibe eine Funktion `max3(a, b, c)`, die das Maximum von drei Zahlen zurückgibt. _Verwende dazu die `max2` Funktion!_
++++Lösung|
def max2(a, b):
if a > b:
return a
else:
return b
def max3(a, b, c):
return max2(max2(a, b), c)
print(max3(int(input('a')), int(input('b')), int(input('c'))))
++++
=== Aufgabe A2: Sortieren ===
* Teil 1: Drei Zahlen sollen eingegeben werden und danach in absteigender Reihenfolge der Grösse ausgegeben werden.
++++Lösung:|
def sort(a, b, c):
if a > b:
if b > c:
print(a, b, c)
elif a > c:
print(a, c, b)
else:
print(c, a, b)
elif b > c:
if a > c:
print(b, a, c)
else:
print(b, c, a)
else:
print(c, b, a)
sort(input(), input(), input())
++++
* (Ausgeblendet): Teil 2: Schreibe Code um als Funktion `my_sort(a,b,c)`, die die drei Zahlen a,b,c sortiert und richtig geordnet in eine Liste schreibt. Die Liste wird zurückgegeben.
=== Aufgabe A3: Subtraction Game ===
* Spiele mit einer Kollegin/einem Kollegen nochmals das Subtraction Game (Spiel mit 21 Stiften).
* Programmiere es dann in Python. Die Spielerin soll gegen den Computer spielen und beginnen dürfen. Der Computer soll immer gewinnen, wenn die Spielerin einen unklugen Zug macht.
=== Aufgabe A4: Ratespiel (optional: mittel) ===
Eine geheime Zahl zwischen 0 und 100 wird in einer Variablen gespeichert. Der Spieler versucht solange die geheime Zahl zu erraten, bis er erfolgreich ist.
Zusatzpunkte:
* Das Programm gibt dem Spieler Tipps, z.B. ’Ausgabe: «Die eingegebene Zahl ist zu klein»’
* Die Anzahl Fehlversuche wird gezählt und am Schluss ausgegeben.
=== Aufgabe A5: Ratespiel umgekehrt (optional: mittel) ===
Der Spieler merkt sich eine geheime Zahl zwischen 0 und 100, der Computer soll sie erraten. Der Spieler soll dem Computer bei jedem Versuch mitteilen, ob die gesuchte Zahl kleiner oder grösser als die Vermutung ist:
* Ist die geheime Zahl kleiner als die Vermutung, muss der Spieler `<` eingeben.
* Ist die geheime Zahl grösser als die Vermutung, muss der Spieler `>` eingeben.
* Ist die geheime Zahl erraten, soll `=` eingegeben werden.
Zusatzpunkte:
* Der Computer detektiert, wenn der Spieler gelogen hat.
===== Mathematische Algorithmen =====
==== Aufgaben B ====
=== Aufgabe B1: Einfache (math.) Algorithmen ===
Schreibe für jede Aufgabe eine Funktion, die passende Argumente entgegennimmt und das Resultat zurück gibt.
Schreibe alle Funktionen selbst und verwende nur ganz rudimentäre Sprachelemente und keine vordefinierten Funktionen.
- Multiplikation durch Additionen ausdrücken
- Hoch-Rechnen durch Multiplikation ausdrücken
- Hoch-Rechnen durch Additionen ausdrücken
- Ganzzahldivision mit Rest mit Addition und Subtraktion
- Entscheiden ob eine beliebige Zahl eine Zweierpotenz ist oder nicht
++++Hinweise:|
* $7*3 = 0 + 3 + 3 + 3 + 3 + 3 + 3 + 3$
* Wir benötigen eine Schleife, die 7 mal 3 zum Resultat addiert.
* Ausserhalb der Schleife deklarieren wir eine Variable, die das Resultat enthält und zu Beginn 0 ist, z.B. `result = 0`.
* Wie lautet die Rechnung für das Hoch-Rechnen mit Multiplikation? Und was ist der Initialwert von `result`?
++++
++++Lösung:|
def multiply(a, b):
"""Multipliziert zwei natürliche Zahlen ohne Verwendung der Python-Multiplikation."""
result = 0 # Null ist das neutrale Element bezüglich der Addition.
while b > 0:
result = result + a
b = b - 1
return result
def exponentiate(a, b):
"""Berechnet a hoch b nur mit Addition."""
result = 1 # Eins ist das neutrale Element bezüglich der Multiplikation.
while b > 0:
result = multiply(result, a)
b = b - 1
return result
def divide(dividend, divisor):
"""Berechnet die Ganzzahldivision mit Rest nur mit Addition & Subtraktion."""
quotient = 0
while dividend >= divisor:
dividend = dividend - divisor
quotient = quotient + 1
# Jetzt ist dividend kleiner als divisor - dividend ist nun der Rest.
# In Python können wir mehrere Werte zurückgeben, durch Komma getrennt:
return quotient, dividend
def is_power_of_2(n):
"""Gibt True zurück, falls n eine Zweierpotenz ist, sonst False."""
test = 1
while test < n:
test = multiply(test, 2)
return test == n
a = input("a")
b = input("b")
print(str(a) + " * " + str(b) + " = " + str(multiply(a, b)))
print(str(a) + " ^ " + str(b) + " = " + str(exponentiate(a, b)))
quotient, rest = divide(a, b)
print(str(a) + "/" + str(b) + " = " + str(quotient) + " Rest " + str(rest))
print(str(a) + " ist eine Zweierpotenz: " + str(is_power_of_2(a)))
print(str(b) + " ist eine Zweierpotenz: " + str(is_power_of_2(b)))
++++
=== Aufgabe B2: Quersumme ===
Die [[wpde>Quersumme]] einer Zahl ist die Summe all ihrer Ziffern. Die Quersumme beispielsweise von $413$ ist $4 + 1 + 3 = 8$.
Schreibe eine Funktion `quersumme(x)`, die die Quersumme von `x` zurückgibt!
++++Zuerst ohne diese Hinweise probieren!|
* Benütze `x % 10` um den Wert der hintersten Ziffer zu berechnen!
* Mit einer geeigneten Division kannst du auf die nächste Stelle vorrücken.
* Wann muss die `while`-Schleife abbrechen?
++++
++++Lösung:|
def quersumme(x):
summe = 0
while x > 0:
ziffer = x % 10
summe = summe + ziffer
x = x // 10
return summe
print(quersumme(413))
++++
==== Primzahlen ====
=== Theorie ===
* Was ist eine Primzahl?
* Wenn nötig: Nachlesen auf [[wpde>Primzahl]] (erster Satz)!
* Primzahl-Test:
* Eine Funktion, die herausfindet (Also `True` oder `False` _zurückgibt_), ob eine Zahl prim ist.
* Wieviele Parameter hat die Funktion `is_prime`?
* Teiler-Test:
* Eine Funktion, die herausfindet (_zurückgibt_), ob eine Zahl `t` ein Teiler ist der Zahl `n`.
* Wieviele Parameter hat die Funktion `is_divisor`?
=== Auftrag zu Primzahlen ===
* in 2er-Gruppen auf Papier (kein Python!)
* Vorgehen:
* Algorithmus für Primzahltest überlegen, in 2er-Gruppe besprechen,Notizen machen: Variablen? Schleifen?
* Mit Lehrperson besprechen
* In Python: Funktion `is_prime(n)` implementieren
* Fertig? siehe Zusatzauftrag und Aufgaben unten
++++Hinweise|
* Schreibe zuerst die Funktion `is_divisor` und teste sie:
* Wie finden wir heraus, ob `t` ein Teiler von `n` ist? Können wir das mit einer einzelnen Berechnung tun statt als [[gf_informatik:algorithmen_i#aufgabe_c4_zusatzaufgabeteilertest|Schleife]]?
* **Hinweis**: Schau dir dir [[gf_informatik:programmieren_ii:variablen_verzweigungen_schleifen#einfache_rechnungen|mathematischen Operationen in Python]] nochmals an.
* Welche Operation könnte praktisch sein, um die Teilbarkeit zu entscheiden?
* **Hinweis 2**: `t` teilt `n` genau dann, wenn der Rest der Division $\frac{n}{t}$ null ist...
* Schreibe `is_prime` erst, wenn `is_divisor` funktioniert.
* Wie hilft uns `is_divisor` bei der Umsetzung des Primzahltests?
++++
**Zusatzauftrag:**
* Wie kannst du den Algorithmus optimieren? Mache einen Plan und diskutiere diesen mit der Lehrperson.
* Schreibe eine optimierte Version der Funktion unter dem Namen `is_prime_2`
++++Lösung:|
import math
def is_divisor(dividend, divisor):
"""Gibt True zurück, wenn divisor ein ganzzahliger Teiler von dividend ist, sonst False."""
return dividend % divisor == 0
def is_prime(n):
"""Gibt True zurück, falls n eine Primzahl ist, sonst False."""
if n < 2:
return False
i = 2
# Es reicht, bis zur Wurzel von n zu testen - gäbe es einen grösseren Teiler t so dass
# t*x == n, dann müsste x kleiner sein als Wurzel(n) und wir hätten x bereits gefunden.
while t <= math.sqrt(n):
if is_divisor(n, t):
# Wir haben einen Teiler gefunden -> keine Primzahl, beenden.
return False
t = t + 1
# Keinen Teiler gefunden -> wir haben eine Primzahl!
return True
++++
=== Aufgabe B3: Primfaktorzerlegung ===
* Jede positive natürliche Zahl kann geschrieben werden als Multiplikation von Primzahlen. Diese Primfaktorzerlegung (PFZ) ist eindeutig.
* Bsp. Primfaktoren für $45$ sind: $3,3,5$ (weil: $3\cdot3\cdot5 = 45$)
* Primfaktorzerlegung ist extrem wichtig z.B. für Verschlüsselungsalgorithmen
* Schreibe eine Funktion `prime_factors(x)`, die eine Zahl x entgegennimmt und deren (geordnete) Primfaktoren von x ausgibt.
++++Lösung:|
Mit den Funktionen `is_prime` und `is_divisor` von oben:
def next_prime(n):
"""Gibt die nächstgrössere Primzahl grösser als n zurück."""
next = n + 1
while not is_prime(next):
next = next + 1
return next
def prime_factors(n):
"""Gibt die Prim-Faktoren von n in aufsteigender Folge zurück."""
factor = 2 # first prime
remainder = n
# Divide n by the increasing prime numbers until we reach 1.
while remainder > 1:
# For each prime, divide the remainder as long as the prime is
# a divisor.
while is_divisor(remainder, factor):
remainder = remainder / factor
print(factor)
# yield factor
# remainder can no longer be divided by factor -> try with the next prime.
factor = next_prime(factor)
prime_factors(int(input()))
++++
==== Weitere anspruchsvolle Algorithmen ====
=== Aufgabe B4: ggT bestimmen ===
* siehe [[gf_informatik:programmieren_zusatzaufgaben#euklidischer_algorithmus|Euklidischer Algorithmus]]
* Schreibe eine Funktion `ggT(x,y)`, die zwei Zahlen `x` und `y` entgegennimmt und den ggT der beiden zurückgibt.
++++Lösung:|
def ggt(a, b):
"""Berechnet den grössten gemeinsamen Teiler von a und b."""
while b > 0:
rest = a % b
a = b
b = rest
return a
print(ggt(544, 391))
++++
=== Aufgabe B5: Quadratwurzel ziehen ===
* siehe [[wpde>Heron-Verfahren]]
* Schreibe eine Funktion `wurzel(x)`, die die Wurzel von `x` auf `0.0001` genau berechnet.
++++Lösung:|
def wurzel(n, precision=0.0001):
"""Quadratwurzel nach Heron."""
# Grundidee: Ein Rechteck mit Fläche n
# wird schrittweise in ein Quadrat transformiert.
# Invariante: a * b == n
# Die wahre Quadratwurzel liegt zwischen a und b.
a = n
b = 1
while a - b > precision:
a = (a + b) / 2 # Mittelwert der beiden Seiten.
b = n/a
return a
print(wurzel(225))
++++