" # in this case, we'll pretend this is a threaded server\n",
" ct = client_thread(clientsocket)\n",
" ct.run()\n",
"\n",
"serversocket.close()"
]
},
},
{
{
"cell_type": "markdown",
"cell_type": "markdown",
"metadata": {},
"metadata": {},
"source": [
"source": [
"Und noch viele weitere schöne Beispiele: https://codegolf.stackexchange.com/questions/15860/"
"Dieser Code enthält das Grundgerüst, um eine auf TCP basierende Serveranwendung zu programmieren. Wenn Sie den Code starten und sich dann mit Hilfe von Telnet mit der Anwendung verbinden (`telnet localhost 8080`), werden alle Eingaben an Sie zurückgespiegelt (\"echo\") und hier in Jupyter ausgegeben. Das ist eine sehr einfache Testanwendung, die aus Sicherheitsgründen nur von Ihrem Rechner aus erreichbar ist. \n",
"\n",
"Falls Ihr Rechner keinen Paketfilter (\"Firewall\") laufen hat und Sie die Zeile mit `localhost` auskommentieren und stattdessen die mit `socket.gethostbyname()` aktivieren, dann ist die Anwendung ggf. auch von anderen Rechnern erreichbar und stellt ziemlich sicher eine Sicherheitslücke dar. Gehen Sie also vorsichtig mit dieser Option um. "
]
]
},
},
{
{
...
@@ -31,9 +79,9 @@
...
@@ -31,9 +79,9 @@
"source": [
"source": [
"## 7 Iteration\n",
"## 7 Iteration\n",
"\n",
"\n",
"Dieses Kapitel ist eine Übersetzung des [Kapitels 8 \"Iteration\"](http://greenteapress.com/thinkpython2/html/thinkpython2008.html) von Allen B. Downey. \n",
"Dieses Kapitel ist eine Übersetzung des [Kapitels 7 \"Iteration\"](http://greenteapress.com/thinkpython2/html/thinkpython2008.html) von Allen B. Downey. \n",
"\n",
"\n",
"Dieses Kapitel handelt von der Iteration - der Möglichkeit, eine Folge von Anweisungen zu wiederholen. Wir haben eine Art der Iteration unter Verwendung der Rekursion schon im [Abschnitt 5.8](seminar05.ipynb#5.8-Rekursion) gesehen und eine andere Art, mit Hilfe der `for`-Schleife in [Abschnitt 4.2](seminar04.ipynb#4.2-Einfache-Wiederholung). In diesem Kapitel lernen wir eine weitere Variante unter Verwendung der `while`-Anweisung kennen. Aber vorher schauen wir uns noch einmal die Zuweisung eines Wertes an eine Variable an. "
"Dieses Kapitel handelt von der Iteration - der Möglichkeit, eine Folge von Anweisungen zu wiederholen. Wir haben eine Art der Iteration unter Verwendung der Rekursion schon im [Abschnitt 5.8](seminar05.ipynb#5.8-Rekursion) gesehen und eine andere Art, mit Hilfe der `for`-Schleife, in [Abschnitt 4.2](seminar04.ipynb#4.2-Einfache-Wiederholung). In diesem Kapitel lernen wir eine weitere Variante unter Verwendung der `while`-Anweisung kennen. Aber vorher schauen wir uns noch einmal die Zuweisung eines Wertes an eine Variable an. "
]
]
},
},
{
{
...
...
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
# Seminar Problemorientierte Programmierung
# Seminar Problemorientierte Programmierung
## Exkurs: Was mir an Python gefällt
## Exkurs: Was mir an Python gefällt
In dieser Rubrik, die immer am Anfang eines Kapitels steht, möchte ich Ihnen zeigen, wofür ich Python nutze und warum ich es mag. Sie werden vielleicht noch nicht verstehen, was ich genau mache, aber Sie sehen damit schon einmal die Möglichkeiten von Python und können später darauf zurückgreifen. Da dies auch ein Exkurs ist, können Sie diese Rubrik gerne auch erst einmal überspringen.
In dieser Rubrik, die immer am Anfang eines Kapitels steht, möchte ich Ihnen zeigen, wofür ich Python nutze und warum ich es mag. Sie werden vielleicht noch nicht verstehen, was ich genau mache, aber Sie sehen damit schon einmal die Möglichkeiten von Python und können später darauf zurückgreifen. Da dies auch ein Exkurs ist, können Sie diese Rubrik gerne auch erst einmal überspringen.
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
# Quellen: https://docs.python.org/3/howto/sockets.html und
# in this case, we'll pretend this is a threaded server
ct = client_thread(clientsocket)
ct.run()
serversocket.close()
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Und noch viele weitere schöne Beispiele: https://codegolf.stackexchange.com/questions/15860/
Dieser Code enthält das Grundgerüst, um eine auf TCP basierende Serveranwendung zu programmieren. Wenn Sie den Code starten und sich dann mit Hilfe von Telnet mit der Anwendung verbinden (`telnet localhost 8080`), werden alle Eingaben an Sie zurückgespiegelt ("echo") und hier in Jupyter ausgegeben. Das ist eine sehr einfache Testanwendung, die aus Sicherheitsgründen nur von Ihrem Rechner aus erreichbar ist.
Falls Ihr Rechner keinen Paketfilter ("Firewall") laufen hat und Sie die Zeile mit `localhost` auskommentieren und stattdessen die mit `socket.gethostbyname()` aktivieren, dann ist die Anwendung ggf. auch von anderen Rechnern erreichbar und stellt ziemlich sicher eine Sicherheitslücke dar. Gehen Sie also vorsichtig mit dieser Option um.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
## 7 Iteration
## 7 Iteration
Dieses Kapitel ist eine Übersetzung des [Kapitels 8 "Iteration"](http://greenteapress.com/thinkpython2/html/thinkpython2008.html) von Allen B. Downey.
Dieses Kapitel ist eine Übersetzung des [Kapitels 7 "Iteration"](http://greenteapress.com/thinkpython2/html/thinkpython2008.html) von Allen B. Downey.
Dieses Kapitel handelt von der Iteration - der Möglichkeit, eine Folge von Anweisungen zu wiederholen. Wir haben eine Art der Iteration unter Verwendung der Rekursion schon im [Abschnitt 5.8](seminar05.ipynb#5.8-Rekursion) gesehen und eine andere Art, mit Hilfe der `for`-Schleife in [Abschnitt 4.2](seminar04.ipynb#4.2-Einfache-Wiederholung). In diesem Kapitel lernen wir eine weitere Variante unter Verwendung der `while`-Anweisung kennen. Aber vorher schauen wir uns noch einmal die Zuweisung eines Wertes an eine Variable an.
Dieses Kapitel handelt von der Iteration - der Möglichkeit, eine Folge von Anweisungen zu wiederholen. Wir haben eine Art der Iteration unter Verwendung der Rekursion schon im [Abschnitt 5.8](seminar05.ipynb#5.8-Rekursion) gesehen und eine andere Art, mit Hilfe der `for`-Schleife, in [Abschnitt 4.2](seminar04.ipynb#4.2-Einfache-Wiederholung). In diesem Kapitel lernen wir eine weitere Variante unter Verwendung der `while`-Anweisung kennen. Aber vorher schauen wir uns noch einmal die Zuweisung eines Wertes an eine Variable an.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 7.1 Neuzuweisung
### 7.1 Neuzuweisung
Wie Sie vielleicht schon herausgefunden haben, ist es erlaubt, mehr als nur eine Zuweisung an die selbe Variable durchzuführen. Durch eine neue Zuweisung verweist eine existierende Variable auf einen neuen Wert (und nicht mehr auf den alten Wert).
Wie Sie vielleicht schon herausgefunden haben, ist es erlaubt, mehr als nur eine Zuweisung an die selbe Variable durchzuführen. Durch eine neue Zuweisung verweist eine existierende Variable auf einen neuen Wert (und nicht mehr auf den alten Wert).
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
x = 5
x = 5
print(x)
print(x)
x = 7
x = 7
print(x)
print(x)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Wenn wir `x` beim ersten Mal ausgeben, ist sein Wert 5; beim zweiten Mal ist sein Wert 7.
Wenn wir `x` beim ersten Mal ausgeben, ist sein Wert 5; beim zweiten Mal ist sein Wert 7.
Die folgende Abbildung zeigt, wie diese **Neuzuweisung** (*reassignment*) in einem Zustandsdiagramm aussieht.
Die folgende Abbildung zeigt, wie diese **Neuzuweisung** (*reassignment*) in einem Zustandsdiagramm aussieht.
An dieser Stelle möchte ich auf eine häufige Ursache für Verwechslungen hinweisen. Da Python das Gleichheitszeichen (`=`) für die Zuweisung verwendet, ist es verlockend, eine Anweisung wie `a = b` wie eine mathematische Aussage der Gleichheit zu interpretieren, das heisst, die Behauptung, dass `a` und `b` gleich seien. Aber diese Interpretation ist falsch!
An dieser Stelle möchte ich auf eine häufige Ursache für Verwechslungen hinweisen. Da Python das Gleichheitszeichen (`=`) für die Zuweisung verwendet, ist es verlockend, eine Anweisung wie `a = b` wie eine mathematische Aussage der Gleichheit zu interpretieren, das heisst, die Behauptung, dass `a` und `b` gleich seien. Aber diese Interpretation ist falsch!
Erstens ist Gleichheit eine symmetrische Beziehung und die Zuweisung ist es nicht. Beispielsweise gilt in der Mathematik: wenn $a=7$, dann ist auch $7=a$. Aber in Python ist die Anweisung `a = 7` erlaubt und `7 = a` ist es nicht.
Erstens ist Gleichheit eine symmetrische Beziehung und die Zuweisung ist es nicht. Beispielsweise gilt in der Mathematik: wenn $a=7$, dann ist auch $7=a$. Aber in Python ist die Anweisung `a = 7` erlaubt und `7 = a` ist es nicht.
Außerdem ist in der Mathematik eine Aussage über die Gleichheit entweder wahr oder falsch und gilt durchgängig. Wenn $a = b$ jetzt gilt, dann wird $a$ stets gleich $b$ sein. Aber in Python kann eine Zuweisung zwei Variablen gleich machen, sie müssen aber nicht durchgängig gleich bleiben:
Außerdem ist in der Mathematik eine Aussage über die Gleichheit entweder wahr oder falsch und gilt durchgängig. Wenn $a = b$ jetzt gilt, dann wird $a$ stets gleich $b$ sein. Aber in Python kann eine Zuweisung zwei Variablen gleich machen, sie müssen aber nicht durchgängig gleich bleiben:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
a = 5
a = 5
b = a # a und b sind jetzt gleich
b = a # a und b sind jetzt gleich
a = 3 # a und b sind nicht mehr gleich
a = 3 # a und b sind nicht mehr gleich
print(b)
print(b)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Die dritte Zeile ändert den Wert von `a` aber dadurch ändert sich nicht der Wert von `b`, so dass die beiden Variablen nicht mehr gleich sind.
Die dritte Zeile ändert den Wert von `a` aber dadurch ändert sich nicht der Wert von `b`, so dass die beiden Variablen nicht mehr gleich sind.
Variablen neue Werte zuzuweisen ist oft nützlich, aber Sie sollten vorsichtig damit umgehen. Wenn sich die Werte von Variablen häufig ändern, ist der Code schwerer zu lesen und zu debuggen.
Variablen neue Werte zuzuweisen ist oft nützlich, aber Sie sollten vorsichtig damit umgehen. Wenn sich die Werte von Variablen häufig ändern, ist der Code schwerer zu lesen und zu debuggen.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 7.2 Variablen aktualisieren
### 7.2 Variablen aktualisieren
Eine übliche Art der Neuzuweisung ist eine **Aktualisierung** (*update*), bei der der neue Wert vom alten Wert abhängt:
Eine übliche Art der Neuzuweisung ist eine **Aktualisierung** (*update*), bei der der neue Wert vom alten Wert abhängt:
```python
```python
x=x+1
x=x+1
```
```
Das bedeutet "nimm' den aktuellen Wert von `x`, füge eins hinzu und aktualisiere dann `x` mit dem neuen Wert".
Das bedeutet "nimm' den aktuellen Wert von `x`, füge eins hinzu und aktualisiere dann `x` mit dem neuen Wert".
Wenn wir versuchen eine Variable zu aktualisieren, die nicht existiert, erhalten wir einen Fehler, denn Python evaluiert die rechte Seite der Zuweisung bevor es den Wert ver Variablen auf der linken Seite zuweist:
Wenn wir versuchen eine Variable zu aktualisieren, die nicht existiert, erhalten wir einen Fehler, denn Python evaluiert die rechte Seite der Zuweisung bevor es den Wert ver Variablen auf der linken Seite zuweist:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
y = y + 1
y = y + 1
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Bevor wir eine Variable aktualisieren können, müssen wir sie **initialisieren**, typischerweise mittels einer Zuweisung:
Bevor wir eine Variable aktualisieren können, müssen wir sie **initialisieren**, typischerweise mittels einer Zuweisung:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
y = 0
y = 0
y = y + 1
y = y + 1
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Das Aktualisieren einer Variable mittels Addition der Zahl 1 wird **inkrementieren** genannt, das Subtrahieren einer 1 **dekrementieren**.
Das Aktualisieren einer Variable mittels Addition der Zahl 1 wird **inkrementieren** genannt, das Subtrahieren einer 1 **dekrementieren**.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 7.3 Die `while`-Anweisung
### 7.3 Die `while`-Anweisung
Computer werden häufig dazu genutzt, um sich wiederholende Aufgaben zu automatisieren. Identische oder ähnliche Aufgaben zu wiederholen ohne dabei Fehler zu machen, ist etwas was Computer sehr gut können und Menschen eher schlecht. In einem Computerprogramm wird die Wiederholung auch als **Iteration** bezeichnet.
Computer werden häufig dazu genutzt, um sich wiederholende Aufgaben zu automatisieren. Identische oder ähnliche Aufgaben zu wiederholen ohne dabei Fehler zu machen, ist etwas was Computer sehr gut können und Menschen eher schlecht. In einem Computerprogramm wird die Wiederholung auch als **Iteration** bezeichnet.
Wir haben bereits zwei Funktionen gesehen, `countdown` und `print_t`, die mit Hilfe einer Rekursion eine Wiederholung durchführen. Da Wiederholung sehr häufig benötigt wird, bietet in Python Sprachkonstrukte die das vereinfachen. Eines ist die `for`-Anweisung, die wir in [Abschnitt 4.2](seminar04.ipynb#4.2-Einfache-Wiederholung) kennengelernt haben. Darauf kommen wir später noch einmal zurück.
Wir haben bereits zwei Funktionen gesehen, `countdown` und `print_t`, die mit Hilfe einer Rekursion eine Wiederholung durchführen. Da Wiederholung sehr häufig benötigt wird, bietet in Python Sprachkonstrukte die das vereinfachen. Eines ist die `for`-Anweisung, die wir in [Abschnitt 4.2](seminar04.ipynb#4.2-Einfache-Wiederholung) kennengelernt haben. Darauf kommen wir später noch einmal zurück.
Eine andere Möglichkeit ist die `while`-Anweisung. Dies ist eine Version von `countdown` die eine `while`-Schleife verwendet:
Eine andere Möglichkeit ist die `while`-Anweisung. Dies ist eine Version von `countdown` die eine `while`-Schleife verwendet:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def countdown(n):
def countdown(n):
while n > 0:
while n > 0:
print(n)
print(n)
n = n - 1
n = n - 1
print("Abheben!")
print("Abheben!")
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Wir können die `while`-Anweisung fast so lesen, als wäre es natürliche Sprache. Es bedeutet "Solange `n` größer als 0 ist, zeige den Wert von `n` und dann dekrementiere `n`. Sobald 0 erreicht ist, gib das Wort `Abheben!` aus."
Wir können die `while`-Anweisung fast so lesen, als wäre es natürliche Sprache. Es bedeutet "Solange `n` größer als 0 ist, zeige den Wert von `n` und dann dekrementiere `n`. Sobald 0 erreicht ist, gib das Wort `Abheben!` aus."
Der Kontrollfluss der `while`-Schleife etwas formaler ausgedrückt sieht so aus:
Der Kontrollfluss der `while`-Schleife etwas formaler ausgedrückt sieht so aus:
1. Bestimme ob die Bedingung wahr oder falsch ist.
1. Bestimme ob die Bedingung wahr oder falsch ist.
2. Wenn die Bedingung unwahr ist, beende die `while`-Schleife und fahre mit der Ausführung der nächsten Anweisung nach dem eingerückten Block von Anweisungen fort.
2. Wenn die Bedingung unwahr ist, beende die `while`-Schleife und fahre mit der Ausführung der nächsten Anweisung nach dem eingerückten Block von Anweisungen fort.
3. Wenn die Bedingung wahr ist, führe die eingerückte Folge von Anweisungen im Schleifenrumpf aus und gehe dann zu Schritt 1.
3. Wenn die Bedingung wahr ist, führe die eingerückte Folge von Anweisungen im Schleifenrumpf aus und gehe dann zu Schritt 1.
Diese Art von Kontrollfluss wird Schleife genannt, weil der dritte Schritt wieder zum ersten Schritt springt und damit den Kreis (Schleife) schließt. (Im Englischen Original passt es besser: *This type of flow is called a loop because the third step loops back around to the top*.)
Diese Art von Kontrollfluss wird Schleife genannt, weil der dritte Schritt wieder zum ersten Schritt springt und damit den Kreis (Schleife) schließt. (Im Englischen Original passt es besser: *This type of flow is called a loop because the third step loops back around to the top*.)
Der Schleifenrumpf sollte den Wert einer oder mehrerer Variablen ändern, so dass die Bedingung irgendwann einmal unwahr wird und die Schleife beendet wird. Ansonsten wiederholt sich die Schleife für immer, was **Endlosschleife** (*infinite loop*) genannt wird.
Der Schleifenrumpf sollte den Wert einer oder mehrerer Variablen ändern, so dass die Bedingung irgendwann einmal unwahr wird und die Schleife beendet wird. Ansonsten wiederholt sich die Schleife für immer, was **Endlosschleife** (*infinite loop*) genannt wird.


Im Fall von `countdown` können wir zeigen, dass die Schleife beendet wird: wenn `n` Null oder negativ ist, dann wird die Schleife niemals ausgeführt. Ansonsten wird `n` bei jedem Schleifendurchlauf verringert, so dass wir irgendwann 0 erreichen.
Im Fall von `countdown` können wir zeigen, dass die Schleife beendet wird: wenn `n` Null oder negativ ist, dann wird die Schleife niemals ausgeführt. Ansonsten wird `n` bei jedem Schleifendurchlauf verringert, so dass wir irgendwann 0 erreichen.
Bei anderen Schleifen ist das nicht unbedingt so einfach zu sehen, zum Beispiel hier:
Bei anderen Schleifen ist das nicht unbedingt so einfach zu sehen, zum Beispiel hier:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def sequence(n):
def sequence(n):
while n != 1:
while n != 1:
print(n)
print(n)
if n % 2 == 0: # n ist gerade
if n % 2 == 0: # n ist gerade
n = n / 2
n = n / 2
else: # n ist ungerade
else: # n ist ungerade
n = n*3 + 1
n = n*3 + 1
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Die Schleifenbedingung ist hier `n != 1`, daher läuft die Schleife so lange, bis `n` gleich `1` ist, wodurch die Bedingung nicht mehr erfüllt ist.
Die Schleifenbedingung ist hier `n != 1`, daher läuft die Schleife so lange, bis `n` gleich `1` ist, wodurch die Bedingung nicht mehr erfüllt ist.
Bei jedem Schleifendurchlauf gibt das Programm den Wert von `n` aus und prüft dann, ob es eine gerade oder eine ungerade Zahl ist. Falls `n` eine gerade Zahl ist, wird `n` durch zwei geteilt. Falls `n` ungerade ist, wird der Wert von `n` ersetzt durch `n*3 + 1`. Übergeben wir der Funktion `sequence` beispielsweise 3 als Argument, dann sind die sich ergebenden Werte von `n` 3, 10, 5, 16, 8, 4, 2, 1. Probieren Sie es selbst für verschiedene Argumente aus:
Bei jedem Schleifendurchlauf gibt das Programm den Wert von `n` aus und prüft dann, ob es eine gerade oder eine ungerade Zahl ist. Falls `n` eine gerade Zahl ist, wird `n` durch zwei geteilt. Falls `n` ungerade ist, wird der Wert von `n` ersetzt durch `n*3 + 1`. Übergeben wir der Funktion `sequence` beispielsweise 3 als Argument, dann sind die sich ergebenden Werte von `n` 3, 10, 5, 16, 8, 4, 2, 1. Probieren Sie es selbst für verschiedene Argumente aus:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Da `n` manchmal wächst und manchmal schrumpft gibt es keinen offensichtlichen Beweis, dass `n` jemals 1 erreichen wird oder das Programm beendet wird. Für einige bestimmte Werte von `n` können wir zeigen, dass das Programm beendet wird. Wenn beispielsweise der Startwert eine Potenz von 2 ist, dann ist `n` bei jedem Schleifendurchlauf eine gerade Zahl (und wird daher halbiert) bis die Schleife den Wert 1 erreicht. Das eben genannte Beispiel endet mit einer solchen Folge, die durch die Zahl 16 beginnt.
Da `n` manchmal wächst und manchmal schrumpft gibt es keinen offensichtlichen Beweis, dass `n` jemals 1 erreichen wird oder das Programm beendet wird. Für einige bestimmte Werte von `n` können wir zeigen, dass das Programm beendet wird. Wenn beispielsweise der Startwert eine Potenz von 2 ist, dann ist `n` bei jedem Schleifendurchlauf eine gerade Zahl (und wird daher halbiert) bis die Schleife den Wert 1 erreicht. Das eben genannte Beispiel endet mit einer solchen Folge, die durch die Zahl 16 beginnt.
Die schwierige Frage ist, ob wir beweisen können, dass dieses Programm für *jeden* positiven Wert von `n` beendet wird. Bis jetzt hat es noch niemand geschafft, dies zu beweisen *oder* das Gegenteil zu beweisen (siehe https://de.wikipedia.org/wiki/Collatz-Problem).
Die schwierige Frage ist, ob wir beweisen können, dass dieses Programm für *jeden* positiven Wert von `n` beendet wird. Bis jetzt hat es noch niemand geschafft, dies zu beweisen *oder* das Gegenteil zu beweisen (siehe https://de.wikipedia.org/wiki/Collatz-Problem).
Schreiben Sie als Übung die Funktion `print_n` aus [Abschnitt 5.8](seminar05.ipynb#5.8-Rekursion) so um, dass eine Schleife statt der Rekursion verwendet wird:
Schreiben Sie als Übung die Funktion `print_n` aus [Abschnitt 5.8](seminar05.ipynb#5.8-Rekursion) so um, dass eine Schleife statt der Rekursion verwendet wird:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def print_n(s, n):
def print_n(s, n):
# Implementieren Sie hier die Funktion mit Hilfe einer Schleife und ohne Rekursion
# Implementieren Sie hier die Funktion mit Hilfe einer Schleife und ohne Rekursion
# Testaufruf
# Testaufruf
print_n("hallo", 3)
print_n("hallo", 3)
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 7.4 `break`
### 7.4 `break`
Manchmal wissen wir nicht, dass es Zeit wird eine Schleife zu beenden bevor wir den Schleifenrumpf nicht schon zur Hälfte ausgeführt haben. In einem solchen Fall können wir die `break`-Anweisung nutzen, um eine Schleife zu verlassen.
Manchmal wissen wir nicht, dass es Zeit wird eine Schleife zu beenden bevor wir den Schleifenrumpf nicht schon zur Hälfte ausgeführt haben. In einem solchen Fall können wir die `break`-Anweisung nutzen, um eine Schleife zu verlassen.
Nehmen wir beispielsweise an, wir wollen eine Eingabe von der Nutzerin einlesen bis Sie `fertig` eingibt. Dann könnten wir folgendes schreiben:
Nehmen wir beispielsweise an, wir wollen eine Eingabe von der Nutzerin einlesen bis Sie `fertig` eingibt. Dann könnten wir folgendes schreiben:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
while True:
while True:
line = input('> ')
line = input('> ')
if line == 'fertig':
if line == 'fertig':
break
break
print(line)
print(line)
print('Fertig!')
print('Fertig!')
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Die Schleifenbedingung ist `True`, was stets wahr ist, daher läuft die Schleife so lange, bis die `break`-Anweisung erreicht wird.
Die Schleifenbedingung ist `True`, was stets wahr ist, daher läuft die Schleife so lange, bis die `break`-Anweisung erreicht wird.
Bei jedem Durchlauf wird die Nutzerin aufgefordert, etwas einzugeben. Wenn Sie `fertig` eingibt, dann beendet die `break`-Anweisung die Schleife. Ansonsten gibt das Programm einfach nur aus, was die Nutzerin eingegeben hat und geht zurück zum Anfang der Schleife. Probieren Sie es selbst einmal aus.
Bei jedem Durchlauf wird die Nutzerin aufgefordert, etwas einzugeben. Wenn Sie `fertig` eingibt, dann beendet die `break`-Anweisung die Schleife. Ansonsten gibt das Programm einfach nur aus, was die Nutzerin eingegeben hat und geht zurück zum Anfang der Schleife. Probieren Sie es selbst einmal aus.
Diese Art eine `while`-Schleife zu nutzen ist üblich, denn wir können die Bedingung überall innerhalb der Schleife prüfen (nicht nur am Anfang) und wir können die Abbruchbedingung positiv formulieren ("beende die Schleife, wenn folgendes passiert") statt negativ ("fahre fort bis folgendes passiert").
Diese Art eine `while`-Schleife zu nutzen ist üblich, denn wir können die Bedingung überall innerhalb der Schleife prüfen (nicht nur am Anfang) und wir können die Abbruchbedingung positiv formulieren ("beende die Schleife, wenn folgendes passiert") statt negativ ("fahre fort bis folgendes passiert").
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 7.5 Quadratwurzeln
### 7.5 Quadratwurzeln
Schleifen werden häufig in Programmen genutzt, die numerische Werte berechnen, indem sie mit einem Näherungswert beginnen und diesen iterativ verbessern.
Schleifen werden häufig in Programmen genutzt, die numerische Werte berechnen, indem sie mit einem Näherungswert beginnen und diesen iterativ verbessern.
Beispielsweise kann die Quadratwurzel einer Zahl mit dem [Newton-Verfahren](https://de.wikipedia.org/wiki/Newton-Verfahren) berechnet werden. Angenommen, wir wollen die Quadratwurzel von $a$ berechnen. Wenn wir mit einem (fast beliebigen) Näherungswert $x$ beginnen, können wir einen besseren Näherungswert $y$ mit der folgenden Formel berechnen:
Beispielsweise kann die Quadratwurzel einer Zahl mit dem [Newton-Verfahren](https://de.wikipedia.org/wiki/Newton-Verfahren) berechnet werden. Angenommen, wir wollen die Quadratwurzel von $a$ berechnen. Wenn wir mit einem (fast beliebigen) Näherungswert $x$ beginnen, können wir einen besseren Näherungswert $y$ mit der folgenden Formel berechnen:
\begin{equation}
\begin{equation}
y = \frac{x + a/x}{2}
y = \frac{x + a/x}{2}
\end{equation}
\end{equation}
Wenn beispielsweise $a$ gleich 4 ist und $x$ gleich 3:
Wenn beispielsweise $a$ gleich 4 ist und $x$ gleich 3:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
a = 4
a = 4
x = 3
x = 3
y = (x + a/x) / 2
y = (x + a/x) / 2
y
y
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Das Ergebnis ist näher an der richtigen Antwort ($\sqrt{4} = 2). Wenn wir den Vorgang mit dem neuen Näherungswert wiederholen, kommen wir noch näher heran:
Das Ergebnis ist näher an der richtigen Antwort ($\sqrt{4} = 2). Wenn wir den Vorgang mit dem neuen Näherungswert wiederholen, kommen wir noch näher heran:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
x = y
x = y
y = (x + a/x) / 2
y = (x + a/x) / 2
y
y
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Nach ein paar mehr Aktualisierungen ist die Näherung fast exakt:
Nach ein paar mehr Aktualisierungen ist die Näherung fast exakt:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
x = y
x = y
y = (x + a/x) / 2
y = (x + a/x) / 2
y
y
```
```
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
x = y
x = y
y = (x + a/x) / 2
y = (x + a/x) / 2
y
y
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Im Allgemeinen wissen wir anfangs nicht, wie viele Schritte nötig sind, um die richtige Antwort zu erhalten, aber wir wissen es, wenn sich der Näherungswert nicht mehr verändert:
Im Allgemeinen wissen wir anfangs nicht, wie viele Schritte nötig sind, um die richtige Antwort zu erhalten, aber wir wissen es, wenn sich der Näherungswert nicht mehr verändert:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
x = y
x = y
y = (x + a/x) / 2
y = (x + a/x) / 2
y
y
```
```
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
x = y
x = y
y = (x + a/x) / 2
y = (x + a/x) / 2
y
y
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Sobald `x == y` gilt, können wir abbrechen. Im Folgenden eine Schleife, die mit einem Näherungswert `x` beginnt und diesen verbessert, bis er sich nicht mehr ändert:
Sobald `x == y` gilt, können wir abbrechen. Im Folgenden eine Schleife, die mit einem Näherungswert `x` beginnt und diesen verbessert, bis er sich nicht mehr ändert:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
a = 4
a = 4
x = 3
x = 3
while True:
while True:
print(x)
print(x)
y = (x + a/x) / 2
y = (x + a/x) / 2
if y == x:
if y == x:
break
break
x = y
x = y
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Für die meisten Werte von `a` funktioniert das sehr gut aber im Allgemeinen ist es gefährlich, die Gleichheit von Gleitkommazahlen zu testen. Gleitkommazahlen sind nur ungefähr exakt: die meisten rationalen Zahlen wie z.B. 1/3 und irrationale Zahlen wie z.B. $\sqrt{2}$ können nicht exakt als Gleitkommazahl repräsentiert werden.
Für die meisten Werte von `a` funktioniert das sehr gut aber im Allgemeinen ist es gefährlich, die Gleichheit von Gleitkommazahlen zu testen. Gleitkommazahlen sind nur ungefähr exakt: die meisten rationalen Zahlen wie z.B. 1/3 und irrationale Zahlen wie z.B. $\sqrt{2}$ können nicht exakt als Gleitkommazahl repräsentiert werden.
Statt zu prüfen ob `x` und `y` exakt gleich sind ist es sicherer die eingebaute Funktion `abs` zu nutzen, um den Betrag des Unterschieds zwischen den beiden Zahlen zu berechnen:
Statt zu prüfen ob `x` und `y` exakt gleich sind ist es sicherer die eingebaute Funktion `abs` zu nutzen, um den Betrag des Unterschieds zwischen den beiden Zahlen zu berechnen:
```python
```python
if abs(y-x) < epsilon:
if abs(y-x) < epsilon:
break
break
```
```
Wobei wir für `epsilon` einen sehr kleinen Wert wie z.B. `0.0000001` wählen sollten, der bestimmt, welche Näherung gut genug für uns ist.
Wobei wir für `epsilon` einen sehr kleinen Wert wie z.B. `0.0000001` wählen sollten, der bestimmt, welche Näherung gut genug für uns ist.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 7.6 Algorithmen
### 7.6 Algorithmen
Das Newton-Verfahren ist ein klassisches Beispiel für einen **Algorithmus**: ein Prozess zur Lösung einer bestimmten Problemklasse (in diesem Fall die Berechnung von Quadratwurzeln).
Das Newton-Verfahren ist ein klassisches Beispiel für einen **Algorithmus**: ein Prozess zur Lösung einer bestimmten Problemklasse (in diesem Fall die Berechnung von Quadratwurzeln).
Um zu verstehen, was ein Algorithmus ist, hilft es vielleicht, sich etwas anzuschauen, was kein Algorithmus ist. Als Sie (wohl in der Grundschule) gelernt haben, Zahlen mit nur einer Ziffer zu multiplizieren, haben Sie wahrscheinlich die Multiplikationstabelle (das [Kleine Einmaleins](https://de.wikipedia.org/wiki/Einmaleins)) auswendig gelernt. Effektiv haben Sie sich damit also 100 verschiedene Lösungen gemerkt. Diese Art von Wissen ist nicht algorithmisch.
Um zu verstehen, was ein Algorithmus ist, hilft es vielleicht, sich etwas anzuschauen, was kein Algorithmus ist. Als Sie (wohl in der Grundschule) gelernt haben, Zahlen mit nur einer Ziffer zu multiplizieren, haben Sie wahrscheinlich die Multiplikationstabelle (das [Kleine Einmaleins](https://de.wikipedia.org/wiki/Einmaleins)) auswendig gelernt. Effektiv haben Sie sich damit also 100 verschiedene Lösungen gemerkt. Diese Art von Wissen ist nicht algorithmisch.
Aber wenn Sie "faul" waren, haben Sie vielleicht ein paar Tricks gelernt. Beispielsweise kann man das Produkt einer Zahl $n$ mit 9 berechnen, indem man $n-1$ als erste Ziffer des Ergebnisses aufschreibt und dann $10-n$ als zweite Ziffer anhängt. Dieser Trick ist eine allgemeine Lösung, um jede Zahl mit nur einer Zahl mit 9 zu multiplizieren. Das ist ein Algorithmus!
Aber wenn Sie "faul" waren, haben Sie vielleicht ein paar Tricks gelernt. Beispielsweise kann man das Produkt einer Zahl $n$ mit 9 berechnen, indem man $n-1$ als erste Ziffer des Ergebnisses aufschreibt und dann $10-n$ als zweite Ziffer anhängt. Dieser Trick ist eine allgemeine Lösung, um jede Zahl mit nur einer Zahl mit 9 zu multiplizieren. Das ist ein Algorithmus!
Genauso sind die Verfahren zur schriftlichen Addition (mit Übertrag), Subtraktion und Division Algorithmen. Eine Eigenschaft von Algorithmen ist, dass Sie keine Intelligenz benötigen, um ausgeführt zu werden. Sie sind mechanische Prozesse bei denen jeder Schritt vom vorherigen mittels einfacher und eindeutiger Regeln folgt.
Genauso sind die Verfahren zur schriftlichen Addition (mit Übertrag), Subtraktion und Division Algorithmen. Eine Eigenschaft von Algorithmen ist, dass Sie keine Intelligenz benötigen, um ausgeführt zu werden. Sie sind mechanische Prozesse bei denen jeder Schritt vom vorherigen mittels einfacher und eindeutiger Regeln folgt.
Algorithmen auszuführen ist langweilig aber sie zu entwerfen ist interessant, intellektuell herausforderng und ein wesentlicher Teil der Informatik.
Algorithmen auszuführen ist langweilig aber sie zu entwerfen ist interessant, intellektuell herausforderng und ein wesentlicher Teil der Informatik.
Einige Dinge die Menschen natürlicherweise tun - ohne Schwierigkeiten oder bewusst einen Gedanken daran zu verschwenden - gehören zu den am schwersten repräsentierbaren Algorithmen. Sprachverstehen ist ein gutes Beispiel. Wir alle machen das ständig aber noch niemand konnte richtig erklären *wie* wir das machen - zumindest nicht in Form eines Algorithmus.
Einige Dinge die Menschen natürlicherweise tun - ohne Schwierigkeiten oder bewusst einen Gedanken daran zu verschwenden - gehören zu den am schwersten repräsentierbaren Algorithmen. Sprachverstehen ist ein gutes Beispiel. Wir alle machen das ständig aber noch niemand konnte richtig erklären *wie* wir das machen - zumindest nicht in Form eines Algorithmus.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 7.7 Debugging
### 7.7 Debugging
Sobald Sie größere Programme schreiben werden Sie bemerken, dass Sie mehr Zeit mit Debuggen verbringen. Mehr Programmcode bedeutet halt auch dass es mehr Möglichkeiten gibt, einen Fehler zu machen und mehr Stellen, an denen sich "Bugs" verstecken können.
Sobald Sie größere Programme schreiben werden Sie bemerken, dass Sie mehr Zeit mit Debuggen verbringen. Mehr Programmcode bedeutet halt auch dass es mehr Möglichkeiten gibt, einen Fehler zu machen und mehr Stellen, an denen sich "Bugs" verstecken können.
Eine Möglichkeit die Zeit für das Debuggen zu reduzieren ist "Debugging durch Halbieren" (binäre Suche). Wenn Ihr Programm beispielsweise 100 Zeilen hat und Sie jede Zeile einzeln prüfen würden, dann bräuchten Sie 100 Schritte zum Debuggen.
Eine Möglichkeit die Zeit für das Debuggen zu reduzieren ist "Debugging durch Halbieren" (binäre Suche). Wenn Ihr Programm beispielsweise 100 Zeilen hat und Sie jede Zeile einzeln prüfen würden, dann bräuchten Sie 100 Schritte zum Debuggen.
Stattdessen können Sie versuchen, das Problem zu halbieren. Gehen Sie (ungefähr) zur Hälfte des Programms und suchen Sie dort nach einem Zwischenwert (eine Variable), den Sie überprüfen können. Fügen Sie eine `print`-Anweisung (oder etwas anderes, was einen prüfbare Auswirkung hat) hinzu und starten Sie das Programm.
Stattdessen können Sie versuchen, das Problem zu halbieren. Gehen Sie (ungefähr) zur Hälfte des Programms und suchen Sie dort nach einem Zwischenwert (eine Variable), den Sie überprüfen können. Fügen Sie eine `print`-Anweisung (oder etwas anderes, was einen prüfbare Auswirkung hat) hinzu und starten Sie das Programm.
Wenn diese Überprüfung in der Mitte das falsche Ergebnis ausgibt, muss das Problem in der ersten Hälfte des Programms liegen, ansonsten in der zweiten Hälfte.
Wenn diese Überprüfung in der Mitte das falsche Ergebnis ausgibt, muss das Problem in der ersten Hälfte des Programms liegen, ansonsten in der zweiten Hälfte.
Jedes Mal wenn Sie einen solchen Test durchführen, haben Sie die Anzahl an Codezeilen halbiert, die Sie prüfen müssen. Nach sechs Schritten (was deutlich weniger als 100 ist), sind Sie bei ein oder zwei Programmzeilen angekommen, in denen der Fehler stecken sollte - zumindest theoretisch.
Jedes Mal wenn Sie einen solchen Test durchführen, haben Sie die Anzahl an Codezeilen halbiert, die Sie prüfen müssen. Nach sechs Schritten (was deutlich weniger als 100 ist), sind Sie bei ein oder zwei Programmzeilen angekommen, in denen der Fehler stecken sollte - zumindest theoretisch.
In der Praxis ist oft nicht klar, was die "Mitte des Programms" ist und es ist nicht immer möglich, dort einen Test hinzuzufügen. Es ist nicht sinnvoll, die Zeilen zu zählen und die exakte Mitte zu finden. Denken Sie stattdessen an Stellen im Programm, die Fehler enthalten könnten und bei denen es einfach ist, eine Überprüfung (Debug-Ausgabe) hinzuzufügen. Suchen Sie dann nach einer Stelle, bei der Sie denken, dass die Chance, dass der Fehler davor oder danach ist ungefähr gleich ist.
In der Praxis ist oft nicht klar, was die "Mitte des Programms" ist und es ist nicht immer möglich, dort einen Test hinzuzufügen. Es ist nicht sinnvoll, die Zeilen zu zählen und die exakte Mitte zu finden. Denken Sie stattdessen an Stellen im Programm, die Fehler enthalten könnten und bei denen es einfach ist, eine Überprüfung (Debug-Ausgabe) hinzuzufügen. Suchen Sie dann nach einer Stelle, bei der Sie denken, dass die Chance, dass der Fehler davor oder danach ist ungefähr gleich ist.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 7.8 Glossar
### 7.8 Glossar
Legen wir uns eine Liste mit den wichtigsten Begriffen an, die wir im Kapitel 7 gelernt haben:
Legen wir uns eine Liste mit den wichtigsten Begriffen an, die wir im Kapitel 7 gelernt haben:
- Neuzuweisung:
- Neuzuweisung:
- Aktualisierung:
- Aktualisierung:
- Initialisierung:
- Initialisierung:
- inkrementieren:
- inkrementieren:
- dekrementieren:
- dekrementieren:
- Iteration:
- Iteration:
- Endlosschleife:
- Endlosschleife:
- Algorithmus:
- Algorithmus:
Ergänzen Sie die Liste in eigenen Worten. Das ist eine gute Erinnerungs- und Übungsmöglichkeit.
Ergänzen Sie die Liste in eigenen Worten. Das ist eine gute Erinnerungs- und Übungsmöglichkeit.
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### 7.9 Übung
### 7.9 Übung
#### Aufgabe 1
#### Aufgabe 1
Kopieren Sie die Schleife aus [Abschnitt 7.5](#7.5-Quadratwurzeln) und verkapseln Sie sie in eine Funktion `mysqrt` die einen Parameter `a` erwartet, einen sinnvollen Wert für `x` wählt und eine Näherung für die Quadratwurzel von `a` zurückliefert.
Kopieren Sie die Schleife aus [Abschnitt 7.5](#7.5-Quadratwurzeln) und verkapseln Sie sie in eine Funktion `mysqrt` die einen Parameter `a` erwartet, einen sinnvollen Wert für `x` wählt und eine Näherung für die Quadratwurzel von `a` zurückliefert.
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
# Implementieren Sie hier die Funktion mysqrt
# Implementieren Sie hier die Funktion mysqrt
# Testen Sie hier die Funktion
# Testen Sie hier die Funktion
print("Die Wurzel von 2 ist ungefähr ", mysqrt(2))
print("Die Wurzel von 2 ist ungefähr ", mysqrt(2))
print("Die Wurzel von 23 ist ungefähr ", mysqrt(23))
print("Die Wurzel von 23 ist ungefähr ", mysqrt(23))
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Testen Sie die Funktion, indem Sie eine Funktion `test_square_root` schreiben, die eine Tabelle der folgenden Art ausgibt:
Testen Sie die Funktion, indem Sie eine Funktion `test_square_root` schreiben, die eine Tabelle der folgenden Art ausgibt:
```
```
a mysqrt(a) math.sqrt(a) diff
a mysqrt(a) math.sqrt(a) diff
- --------- ------------ ----
- --------- ------------ ----
1.0 1.0 1.0 0.0
1.0 1.0 1.0 0.0
2.0 1.41421356237 1.41421356237 2.22044604925e-16
2.0 1.41421356237 1.41421356237 2.22044604925e-16
3.0 1.73205080757 1.73205080757 0.0
3.0 1.73205080757 1.73205080757 0.0
4.0 2.0 2.0 0.0
4.0 2.0 2.0 0.0
5.0 2.2360679775 2.2360679775 0.0
5.0 2.2360679775 2.2360679775 0.0
6.0 2.44948974278 2.44948974278 0.0
6.0 2.44948974278 2.44948974278 0.0
7.0 2.64575131106 2.64575131106 0.0
7.0 2.64575131106 2.64575131106 0.0
8.0 2.82842712475 2.82842712475 4.4408920985e-16
8.0 2.82842712475 2.82842712475 4.4408920985e-16
9.0 3.0 3.0 0.0
9.0 3.0 3.0 0.0
```
```
Dabei ist die erste Spalte eine Zahl; `a`, die zweite Spalte ist die Quadratwurzel von `a` die mit `mysqrt` berechnet wurde; die dritte Spalte ist die Quadratwurzel, die mittels `math.sqrt` berechnet wurde; und die vierte Spalte ist der Absolutbetrag des Unterschieds zwischen den beiden Werten.
Dabei ist die erste Spalte eine Zahl; `a`, die zweite Spalte ist die Quadratwurzel von `a` die mit `mysqrt` berechnet wurde; die dritte Spalte ist die Quadratwurzel, die mittels `math.sqrt` berechnet wurde; und die vierte Spalte ist der Absolutbetrag des Unterschieds zwischen den beiden Werten.
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
def test_square_root():
def test_square_root():
# Implementieren Sie hier die Funktion test_square_root
# Implementieren Sie hier die Funktion test_square_root
# Rufen Sie hier die Funktion test_square_root auf
# Rufen Sie hier die Funktion test_square_root auf
test_square_root()
test_square_root()
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
### Aufgabe 2
### Aufgabe 2
Die eingebaute Funktion `eval` erwartet eine Zeichenkette und führt sie dann mit dem Python-Interpreter aus. Beispielsweise:
Die eingebaute Funktion `eval` erwartet eine Zeichenkette und führt sie dann mit dem Python-Interpreter aus. Beispielsweise:
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
eval('1 + 2 * 3')
eval('1 + 2 * 3')
```
```
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
import math
import math
eval('math.sqrt(5)')
eval('math.sqrt(5)')
```
```
%% Cell type:code id: tags:
%% Cell type:code id: tags:
```
```
eval('type(math.pi)')
eval('type(math.pi)')
```
```
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
Schreiben Sie eine Funktion `eval_loop`, die den Nutzer iterativ bittet etwas einzugeben, die eingegebene Zeichenkette mittels `eval` ausführt und schließlich das Ergebnis ausgibt.
Schreiben Sie eine Funktion `eval_loop`, die den Nutzer iterativ bittet etwas einzugeben, die eingegebene Zeichenkette mittels `eval` ausführt und schließlich das Ergebnis ausgibt.
Die Funktion sollte so lange laufen, bis der Nutzer `done` eingibt und dann sollte der Rückgabewert des letzten ausgeführten Ausdrucks ausgegeben werden.
Die Funktion sollte so lange laufen, bis der Nutzer `done` eingibt und dann sollte der Rückgabewert des letzten ausgeführten Ausdrucks ausgegeben werden.
Der Mathematiker [Srinivasa Ramanujan](https://de.wikipedia.org/wiki/S._Ramanujan) hat eine unendliche Folge gefunden die genutzt werden kann, um eine numerische Näherung für 1/$\pi$ zu berechnen:
Der Mathematiker [Srinivasa Ramanujan](https://de.wikipedia.org/wiki/S._Ramanujan) hat eine unendliche Folge gefunden die genutzt werden kann, um eine numerische Näherung für 1/$\pi$ zu berechnen:
(Eventuell ist die Formel [in der Original-Aufgabenstellung](http://greenteapress.com/thinkpython2/html/thinkpython2008.html#hevea_default541) besser zu lesen.)
(Eventuell ist die Formel [in der Original-Aufgabenstellung](http://greenteapress.com/thinkpython2/html/thinkpython2008.html#hevea_default541) besser zu lesen.)
Schreiben Sie eine Funktion `estimate_pi` die diese Formel nutzt, um einen Näherungswert für $\pi$ zu berechnen und zurückzugeben. Sie sollten eine `while`-Schleife nutzen, um die Terme der Summe zu solange berechnen, bis der letzte Term kleiner ist als `1e-15` (was die Python-Notation für $10^{-15}$ ist). Sie können Ihr Ergebnis prüfen, indem Sie es mit `math.pi` vergleichen.
Schreiben Sie eine Funktion `estimate_pi` die diese Formel nutzt, um einen Näherungswert für $\pi$ zu berechnen und zurückzugeben. Sie sollten eine `while`-Schleife nutzen, um die Terme der Summe zu solange berechnen, bis der letzte Term kleiner ist als `1e-15` (was die Python-Notation für $10^{-15}$ ist). Sie können Ihr Ergebnis prüfen, indem Sie es mit `math.pi` vergleichen.
Lösung: http://thinkpython2.com/code/pi.py
Lösung: http://thinkpython2.com/code/pi.py
%% Cell type:markdown id: tags:
%% Cell type:markdown id: tags:
 Speichern Sie dieses Notebook, so dass Ihre Änderungen nicht verlorengehen (nicht auf einem Pool-Rechner). Klicken Sie dazu oben links auf das Disketten-Icon und nutzen Sie beispielsweise einen USB-Stick, E-Mail, Google Drive, Dropbox oder Ihre [HU-Box](https://box.hu-berlin.de/).
 Speichern Sie dieses Notebook, so dass Ihre Änderungen nicht verlorengehen (nicht auf einem Pool-Rechner). Klicken Sie dazu oben links auf das Disketten-Icon und nutzen Sie beispielsweise einen USB-Stick, E-Mail, Google Drive, Dropbox oder Ihre [HU-Box](https://box.hu-berlin.de/).