Aufgaben - Mathematik und ihre Didaktik

Programmiergrundkurs
Aufgaben und Anleitung
Lucas Mann
13.01.2016
1 Übersetzung in Python
Als erstes machen wir uns damit vertraut, wie man in Python Algorithmen schreiben kann. Einen
Algorithmus kannst du folgendermaßen definieren:
def mein_algorithmus(a, b):
Schritt1
Schritt2
...
Dabei ist mein_algorithmus der Name des Algorithmus und a und b sind die Eingabewerte
(auch Parameter genannt). Natürlich kann dein Algorithmus auch mehr (oder weniger) Eingabewerte haben.
Die folgende Tabelle zeigt, wie die einzelnen Schritte eines Algorithmus aus der Umgangssprache in Python übersetzt werden:
Umgangssprache
Python
Eingabe: a, b.
Kein extra Schritt, da in der Algorithmusdefinition enthalten (s.o.)
Ausgabe: r .
Wenn a > 2:
Schritt1
...
Sonst, wenn a < 0:
...
Sonst:
...
Wiederhole solange, wie n > 0:
Schritt1
...
Für k im Bereich(1, n):
...
Setze a = 0
Erhöhe x um n
Wende Algorithmus “alg” auf die Werte n und 3 an.
Speichere das Ergebnis des Algorithmus “alg”, angewendet auf a, in r .
Ausgabe: Ergebnis des Algorithmus “abc”.
return r
if a > 2:
Schritt1
...
elif a < 0:
...
else:
...
while n > 0:
Schritt1
...
for k in range(1, n + 1):
...
a = 0
x = x + n oder x += n
alg(n, 3)
r = alg(a)
return abc()
In Python gibt es verschiedene Arten von Werten, zum Beispiel Zahlen, Wahrheitswerte und
Texte. Die nächste Tabelle zeigt, wie du verschiedene Arten von Werten im Code eintippst:
1
Werttyp
Ganze Zahl
Reelle Zahl
Wahrheitswert
Text
Beispielwerte
0, 5, −14
3,1415
“Wahr”, “Falsch”
“Hello World”
In Python
0, 5, -14
3.1415
True, False
"Hello World"
Wenn man zwei Werte vergleichen möchte (zum Beispiel in einem “Wenn . . . :”), hat man die
folgenden Relationen zur Verfügung:
Mathematisch
Python
=
6=
<
>
≤
≥
==
!=
<
>
<=
>=
Außerdem gibt es die logischen Verknüpfungen not, and und or. Zum Beispiel überprüft
if (a > 0 and b < 0) or (a < 0 and b > 0):
ob a und b verschiedene Vorzeichen haben.
Es folgt ein Beispiel für einen Algorithmus in Umgangsprache und seine Übersetzung in Python:
1. Eingabe: Eine ganze Zahl n.
2. Wenn n < 0:
def gauss_summe(n):
if n < 0:
return "Ungueltiges n"
r = 0
while n > 0:
r = r + n
n = n - 1
return r
2.1. Ausgabe: „Ungültiges n“.
3. Setze r = 0.
4. Wiederhole die folgenden Schritte solange, wie n > 0:
4.1. Erhöhe r um n.
4.2. Verringere n um 1.
5. Ausgabe: r .
Zur Vorbereitung für die folgenden Aufgaben implementiere obigen Algorithmus wie folgt in
Python:
1. Tippe obigen Code in eine Textdatei und gib dieser Datei den Namen algorithmen.py.
2. Öffne ein Terminal, gehe dort mittels cd Pfad zu dem Ordner, in dem sich die Codedatei
befindet.
3. Tippe python3 ein, um Python zu starten.
4. Tippe from algorithmen import * ein, um deine Codedatei zu laden.
5. Nun kannst du alle Algorithmen in der Codedatei benutzen. Tippe zum Beispiel gauss_summe(4)
ein; es erscheint das Ergebnis 10.
Die folgenden Aufgaben verlangen von dir, die im Kurs behandelten Algorithmen in Python zu
übersetzen.
Aufgabe 1. Implementiere den Algorithmus teilt(a, b), welcher zurückgibt, ob die Zahl b
durch die Zahl a teilbar ist. Benutze als Vorbild den im letztwöchigen Kurs erarbeiteten Algorithmus.
Aufgabe 2. Implementiere den Algorithmus ist_prim(n), der zurückgibt, ob die Zahl n eine
Primzahl ist.
Aufgabe 3. Implementiere den Algorithmus fakultaet(n), welcher n! ausrechnet.
Aufgabe 4. Implementiere alle Algorithmen, die in Hausaufgabenserie 12 vorkamen.
2
2 Neue Algorithmen
Hier sind ein paar weitere Aufgaben, für die du dir nun deine eigenen Algorithmen überlegen
musst.
Aufgabe 5. Schreibe einen Algorithmus binomial(n, k), welcher den Binomialkoeffizienten
¡n ¢
k berechnet. Zur Erinnerung: Es gilt
à !
n
n(n − 1)(n − 2) . . . (n − k + 1)
n!
=
.
=
k
k! (n − k)!
k!
Welche der beiden Formeln lässt sich leichter implementieren? Und welche erfordert weniger Rechenaufwand?
Aufgabe 6. Schreibe einen Algorithmus, der die n-te Fibonacci-Zahl F n ausrechnet. Benutze dabei
die folgenden drei Ansätze:
a) Benutze die rekursive Vorschrift
F 0 = 0,
F 1 = 1,
F n = F n−1 + F n−2
für n ≥ 2
in einer Schleife.
b) Benutze die explizite Darstellung
Fn =
wobei φ =
φn − (1 − φ)n
,
p
5
p
1+ 5
2
der Goldene Schnitt ist.
p
Tipp: Zur Berechnung von 5 benutze den Python-Code 5**.5.
c) Die Vorschrift F n = F n−1 + F n−2 kannst du auch direkt implementieren, indem du deinen
Algorithmus sich selbst aufrufen lässt (das nennt man Rekursion). Du musst dann allerdings
aufpassen, dass der Algorithmus irgendwann beendet wird. Wie?
3 Listen
Listen sind ein sehr wichtiger Datentyp in Python. Wie der Name sagt, ist eine Liste eine endliche
geordnete Aneinanderreihung von irgendwelchen Werten (zum Beispiel die Liste aller Primzahlen
von 1 bis 100). Listen werden mit eckigen Klammern geschrieben, also zum Beispiel
l1 = [1, 1, 2, 3, 5, 8]
l2 = ["Hallo", True, 1, -3.2]
l3 = [] # leere Liste
Die folgende Tabelle zeigt ein paar wichtige Operationen mit Listen:
Umgangssprache
Setze den 5-ten Eintrag der Liste l auf „Wahr“
Setze den a-ten Eintrag der Liste l auf den Wert in k
Lies den 3-ten Eintrag der Liste l und speichere ihn in r
Hänge den Text „Python“ hinten an die Liste l an
Erzeuge eine Liste mit 20 True-Einträgen
Python
l[5] = True
l[a] = k
r = l[3]
l.append("Python")
l = [True] * 20
Es ist dabei wichtig zu wissen, dass die Nummern der Einträge immer bei 0 anfangen zu zählen.
In obiger Liste l2 ist also l2[1] = True und l2[0] = "Hallo".
3
Aufgabe 7. Schreibe einen Algorithmus primzahlen(n), der die Liste aller Primzahlen von 1
bis n ausgibt, indem du den bereits implementierten Algorithmus ist_prim(n) benutzt. Teste
die Geschwindigkeit deines Algorithmus für große n und schätze seine Effizienz ein.
Aufgabe 8. Die Collatz-Folge zu einem Startwert n 0 (natürliche Zahl) wird wie folgt schrittweise
berechnet: Sei n die aktuelle Zahl (am Anfang also n = n 0 ). In jedem Schritt tue folgendes:
1. Wenn n gerade ist, nimm als nächste Zahl n2 .
2. Wenn n ungerade ist, nimm als nächste Zahl 3n + 1.
Es ist eine unbewiesene Vermutung, dass diese Folge immer irgendwann bei 1 landet, egal mit
welchem n 0 man beginnt.
Schreibe einen Algorithmus collatz(n0), der die Collatz-Folge mit Startwert n0 berechnet,
bis irgendwann 1 herauskommt, und der die Folge von n0 bis 1 als Liste ausgibt.
4 Ein richtiges Programm
Nachdem wir nun viele interessante Algorithmen geschrieben haben, wollen wir abschließend
einen kleinen Einblick darin bekommen, wie ein richtiges Programm in Python aussieht. Wenn du
Code direkt beim Laden des Programm ausführen willst (statt nur eine Sammlung von Algorithmen zu haben), dann kannst du diesen Code außerhalb aller Algorithmen (am besten darunter)
schreiben, also ohne Einrückung. Damit das Programm mit dem Nutzer interagieren kann, gibt es
zwei wichtige Befehle:
1. Mit print(wert) wird der angegebene Wert ausgegeben. Möchtest du einen Text ausgeben, schreibe ihn in Anführungszeichen (wie bereits weiter oben erklärt), also zum Beispiel
print("Hallo"). Wenn du Werte in den Text einfügen willst, benutze format und geschweifte Klammern, zum Beispiel:
r = 5 + 5
print("Anna ist {} und Bernd ist {} Jahre alt".format(r, 14))
Dadurch werden die an format übergebenen Werte anstelle der geschweiften Klammern
ausgegeben (in der gleichen Reihenfolge). Natürlich kannst du statt direkten Werten (wie
10 und 14) auch die in Variablen (Speicherplätzen) gespeicherten Werte angeben. Das geht
nicht direkt im Text!
2. Mit input(text) wird der Nutzer mittels der Nachricht text aufgefordert, etwas einzugeben. Das Ergebnis dieser Eingabe wird dann von input zurückgegeben und kann direkt
in eine Variable gespeichert werden. Der Typ des Wertes ist dann aber automatisch „Text“;
um diesen Text in eine Zahl zu konvertieren, kannst du int(wert) benutzen.
Hier ein Beispiel für ein Programm, das den Nutzer auffordert, ein n einzugeben und dann n!
ausgibt:
print("Ich kann n! berechnen!")
n = int(input("Bitte gib n ein: "))
r = fakultaet(n)
print("Das Ergebnis ist {}".format(r))
Aufgabe 9. Wähle einen deiner Algorithmen aus und schreibe ein Python-Programm, welches
diesen Algorithmus ausführt. Das heißt es sagt dem Nutzer was es tut, fragt dann die Eingabewerte
ab und gibt schließlich das Ergebnis aus.
4
Der eleganteste Weg, das Programm auszuführen, ist den Befehl python3 datei.py einzutippen (also ohne das -i).
Aufgabe 10. Schreibe das Spiel „Zahlen raten“: Der Computer wählt sich zu Beginn eine zufällige
Zahl zwischen 1 und 1000. In jedem Zug darf der Spieler die Zahl raten und der Computer sagt
ihm, ob seine Eingabe größer, kleiner oder gleich der zufälligen Zahl ist. Wenn der Spieler richtig
rät, gibt der Computer die Anzahl der benötigten Versuche aus.
Hinweis: Tue folgendes, um eine zufällige Zahl zwischen 1 und 1000 zu „berechnen“: Schreibe ganz oben in dein Programm die (uneingerückte!) Zeile import random, um die Zufallsalgorithmen in dein Programm zu laden. Um nun eine zufällige Zahl zu berechnen, benutze
random.randint(1, 1000), also in etwa
import random
...
zahl = random.randint(1, 1000)
...
5 Zusatz
Aufgabe 11. Gesucht sind die Lösungen zu folgendem Kryptogramm:
EINS +EINS = ZW EI.
Dabei steht jeder Buchstabe für eine Ziffer. Der Einfachheit halber erlauben wir, dass zwei verschiedene Buchstaben die gleiche Ziffer haben (Zusatz: Schaffst du es auch sonst?).
Schreibe einen Algorithmus kryptogramm(), welcher alle Lösungen des Kryptogramms berechnet und in einer Liste zurückgibt. Benutze dafür die „brute force“-Methode (= rohe Gewalt),
d.h. gehe alle Möglichkeiten für die Belegungen der 6 Buchstaben durch und überprüfe jeweils, ob
die Gleichung erfüllt ist.
Tipp: Du musst wahrscheinlich for-Schleifen ineinander verschachteln. Dein Algorithmus könnte also folgendermaßen anfangen:
def kryptogramm():
for e in range(0, 10):
for i in range(0, 10):
...
Aufgabe 12. In Aufgabe 7 hast du einen Algorithmus programmiert, der dir die Primzahlen von 1
bis n ausgibt (für ein gegebenes n). Allerdings ist dieser Algorithmus sehr ineffizient und läuft für
großes n nicht mehr in akzeptabler Zeit. Ein wesentlich schnellerer Algorithmus, der das gleiche
Ergebnis erzeugt, ist das Sieb des Eratosthenes.
Die Idee ist folgende: Zu Beginn wird eine Liste ` mit n Einträgen angelegt, wobei erstmal alle
Einträge True sind. Nun werden die folgenden Schritte wiederholt: Suche den kleinsten Index
k ≥ 2, sodass der k-te Eintrag von ` den Wert True hat. Dann ist k eine Primzahl, speichere k also
in eine separate Primzahlliste. Nun gehe alle Vielfachen von k durch und setze die entsprechenden
Einträge in ` auf False.
a) Überlege dir, warum dieser Algorithmus funktioniert. Vergleiche obige Beschreibung mit der
Erklärung auf Wikipedia; ist das der gleiche Algorithmus?
b) Implementiere den Algorithmus eratosthenes(n) nach obigem Vorbild. Vergleiche die
Geschwindigkeit dieses Algorithmus mit dem bereits implementierten primzahlen(n).
5
Tipp 1: Um eine Liste mit n Einträgen True zu erzeugen, kannst du l = [True] * n
benutzen (siehe oben).
Tipp 2: Um alle Vielfachen einer Zahl durchzugehen, kannst du eine for-Schleife benutzen. Man kann nämlich range sogar drei Parameter übergeben, wobei der dritte Parameter
dann die Schrittweite ist. Zum Beispiel:
for k in range(a, b, c):
Eine solche Schleife wird für alle k der Form a, a + c, a + 2c, a + 3c, . . . wiederholt, solange
diese Zahlen kleiner als b sind.
Aufgabe 13. Das Ziel dieser Aufgabe ist es, die bekannte Kreiszahl π zu berechnen.
a) Mithilfe elementarer Analysis kann man zeigen:
µ
¶
1 1 1 1 1
π = 4· 1− + − + −
±...
3 5 7 9 11
Schreibe einen Algorithmus pi(n), welcher die ersten n Additionen/Subtraktionen dieser
Formel ausrechnet und somit eine Näherung für π bestimmt. Teste die Formel für große n –
wie gut ist die Näherung?
b) Ein wesentlich besserer, aber leider auch komplizierter Weg zur Berechnung von π ist folgendermaßen gegeben: Als erstes berechnet man zwei Zahlenfolgen (a n ) und (b n ) durch
folgende rekursive Vorschrift:
p
a 0 = 1,
b 0 = 0.5,
p
a k−1 + b k−1
ak =
,
b k = a k−1 · b k−1 ,
für k ≥ 1.
2
Zu gegebenem n berechnen wir nun
s n = 20 (a 0 − b 0 )2 + 21 (a 1 − b 1 )2 + 22 (a 2 − b 2 )2 + 23 (a 3 − b 3 )2 + · · · + 2n (a n − b n )2 .
Dann ist eine gute Näherung für π gegeben durch
π≈
(a n + b n )2
,
1 − sn
wobei die Näherung besser wird, je größer man n wählt.
Implementiere den Algorithmus pi2(n), welcher eine Näherung für π nach diesem Verfahren berechnet. Berechne pi2(4) und vergleiche die Genauigkeit (und Geschwindigkeit)
dieser Rechnung mit pi(10000). Was fällt auf?
Tipp: Um die Wurzel aus einer Zahl x zu berechnen, kannst du x**.5 benutzen.
Bemerkung: Der zweite Algorithmus ist so schnell, dass man sehr leicht an die Rechengenauigkeit von Python herankommt. In der Tat lässt sich aufgrund dieser Rechengenauigkeit
kein genauerer Wert als pi2(4) bestimmen. Natürlich gibt es Methoden, die Rechengenauigkeit zu erhöhen. Bei Interesse bitte nachfragen.
Aufgabe 14. Schreibe einen kleinen Taschenrechner, welcher die vier Grundrechenarten sowie
Potenzen und Binomialkoeffizienten berechnen kann. Das Programm nimmt als Eingaben zwei
Zahlen a und b und eine Operation und gibt das Ergebnis der entsprechenden Rechnung aus. Die
Operation wird als Text angegeben und kann +, -, *, /, ^ oder b sein.
Tipp: Benutze input(text), um die beiden Zahlen und die Operation vom Nutzer abzufragen.
Bei den Zahlen musst du noch int(...) darumschreiben, um den eingegebenen Text in eine
Zahl umzuwandeln (wie zuvor), bei der Operation nicht (denn diese soll ja als Text behandelt werden).
6