From eb6a21b5fee83f1013dc3e8944e3397e5d0e4e94 Mon Sep 17 00:00:00 2001 From: Michel Schwab <michel.schwab@hu-berlin.de> Date: Wed, 12 Dec 2018 13:25:52 +0100 Subject: [PATCH] Miriam branch11: seminar07 --- notebooks/seminar07.ipynb | 309 +++++++++++++++++++++++++++++--------- 1 file changed, 237 insertions(+), 72 deletions(-) diff --git a/notebooks/seminar07.ipynb b/notebooks/seminar07.ipynb index 2086e33..174243d 100644 --- a/notebooks/seminar07.ipynb +++ b/notebooks/seminar07.ipynb @@ -6,82 +6,55 @@ "source": [ "# Seminar Problemorientierte Programmierung\n", "\n", - "## Exkurs: Was mir an Python gefällt\n", + "## 7 Iteration\n", "\n", - "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.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Quellen: https://docs.python.org/3/howto/sockets.html und \n", - "# http://www.binarytides.com/python-socket-server-code-example/\n", + "[Chapter 7: Iteration](http://greenteapress.com/thinkpython2/html/thinkpython2008.html) \n", "\n", "import socket\n", "\n", - "# function for handling connections. This will be used to create threads\n", - "def client_thread(conn):\n", - " # sending message to connected client\n", - " conn.send(bytearray('Welcome to the server. Type something and hit enter\\n', \"utf-8\")) #send only takes string\n", - " \n", - " # infinite loop so that function do not terminate and thread do not end.\n", - " while True:\n", - " \n", - " # receiving from client\n", - " data = conn.recv(1024)\n", - " if not data: \n", - " break\n", - " # print on server side\n", - " print(data.decode(\"utf-8\"))\n", - " # echo to client side\n", - " reply = bytearray('OK ... ', \"utf-8\") + data\n", - " conn.sendall(reply)\n", - " \n", - " # came out of loop\n", - " conn.close()\n", - " \n", - "# create an INET, STREAMing socket\n", - "serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\n", - "# bind the socket to a public host, and a port\n", - "# serversocket.bind((socket.gethostname(), 8080))\n", - "# use localhost instead \n", - "serversocket.bind((\"localhost\", 8080))\n", - "# become a server socket\n", - "serversocket.listen(5)\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. \n", "\n", + "### Ihre Lernziele:\n", "\n", - "while True:\n", - " # accept connections from outside\n", - " (clientsocket, address) = serversocket.accept()\n", - " # now do something with the clientsocket\n", - " # in this case, we'll pretend this is a threaded server\n", - " ct = client_thread(clientsocket)\n", - " ct.run()\n", + "Beschreiben Sie in 2-3 Stichpunkten kurz was Sie im Seminar heute lernen wollen. Klicken Sie dazu doppelt auf diesen Text und bearbeiten Sie dann den Text:\n", "\n", - "serversocket.close()" + "- \n", + "- \n", + "- " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "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", + "## Exkurs: Was mir an Python gefällt\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. " + "Das [Modul os](https://docs.python.org/3/library/os.html) stellt Funktionen bereit, um Funktionalitäten des Betriebssystems zu nutzen. Beispielsweise können wir damit Verzeichnis-Inhalte auflisten, durch Verzeichnisse navigieren, Informationen zu Dateien bekommen und Dateieigenschaften verändern. Das folgende Programm gibt eine Liste aller Jupyter-Notebooks im aktuellen Verzeichnis zusammen mit der Dateigröße aus und berechnet die Gesamtgröße der Dateien:" ] }, { - "cell_type": "markdown", + "cell_type": "code", + "execution_count": null, "metadata": {}, "source": [ - "## 7 Iteration\n", + "import os\n", + "\n", + "# Tabellenkopf ausgeben\n", + "print(\"Bytes\\tName\")\n", + "print(\"--------------------------------------------------------------\")\n", "\n", - "Dieses Kapitel ist eine Übersetzung des [Kapitels 7 \"Iteration\"](http://greenteapress.com/thinkpython2/html/thinkpython2008.html) von Allen B. Downey. \n", + "# Gesamtgröße in Bytes\n", + "bytes_sum = 0\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. " + "# Inhalt des aktuellen Verzeichnisses durchlaufen\n", + "for entry in os.scandir():\n", + " if entry.is_file() and entry.name.endswith(\".ipynb\"):\n", + " size = entry.stat().st_size\n", + " bytes_sum +=size\n", + " print(\"{:5d}\".format(size), entry.name, sep='\\t')\n", + " \n", + "print(\"--------------------------------------------------------------\")\n", + "print(bytes_sum, \"bytes =\", bytes_sum/1000, \"kilobytes =\", bytes_sum/1000000, \"Megabytes\")" ] }, { @@ -117,9 +90,9 @@ "\n", "An dieser Stelle wollen wir 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! \n", "\n", - "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. \n", + "Zum Einen 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. \n", "\n", - "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:\n" + "Zum Anderen 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. In Python kann eine Zuweisung zwei Variablen gleich machen, sie müssen aber nicht durchgängig gleich bleiben:\n" ] }, { @@ -138,7 +111,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "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.\n", + "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.\n", "\n", "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. " ] @@ -205,9 +178,9 @@ "\n", "Computer werden häufig zur Automatisierung sich wiederholender Aufgaben genutzt. 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. \n", "\n", - "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, gibt es 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.\n", + "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, gibt es 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.\n", "\n", - "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:" ] }, { @@ -230,17 +203,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Wir können die `while`-Anweisung fast so lesen, als wäre es natürliche Sprache: \"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.\"\n", + "Wir können die `while`-Anweisung fast so lesen, als wäre es natürliche Sprache: \"Solange `n` größer als 0 ist, zeige den Wert von `n` an und dann dekrementiere `n`. Sobald 0 erreicht ist, gib das Wort `Abheben!` aus.\"\n", "\n", "Der Kontrollfluss der `while`-Schleife etwas formaler ausgedrückt sieht so aus:\n", "\n", "1. Bestimme ob die Bedingung wahr oder falsch ist.\n", "2. Wenn die Bedingung unwahr ist, beende die `while`-Schleife und fahre mit der Ausführung der nächsten Anweisung nach der eingerückten Folge von Anweisungen fort.\n", - "3. Wenn die Bedingung wahr ist, führe die eingerückte Folge von Anweisungen im Schleifenrumpf aus und gehe dann zu Schritt 1.\n", + "3. Wenn die Bedingung wahr ist, führe die eingerückte Folge von Anweisungen im Schleifenrumpf aus und gehe dann zu Schritt 1 zurück.\n", "\n", "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*.)\n", "\n", - "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.\n", + "Der Schleifenrumpf sollte den Wert einer oder mehrerer Variablen ändern, sodass 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.\n", "\n", "\n", "\n", @@ -290,7 +263,8 @@ "source": [ "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 (2, 4, 8, 16, 32, ...), 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 mir der Zahl 16 beginnt.\n", "\n", - "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).\n", + "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. \n", + "Es hat aber auch noch niemand geschafft das Gegenteil zu beweisen. [Collatz-Problem](https://de.wikipedia.org/wiki/Collatz-Problem).\n", "\n", "\n", "\n", @@ -319,9 +293,9 @@ "source": [ "### 7.4 `break`\n", "\n", - "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.\n", + "Manchmal wissen wir nicht, dass es Zeit wird eine Schleife zu beenden, bis wir den Schleifenrumpf bereits zur Hälfte ausgeführt haben. In einem solchen Fall können wir die `break`-Anweisung nutzen, um eine Schleife zu verlassen.\n", "\n", - "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 Nutzer_in einlesen bis sie `fertig` eingibt. Dann könnten wir folgendes schreiben:" ] }, { @@ -345,7 +319,7 @@ "source": [ "Die Schleifenbedingung ist `True`, was stets wahr ist, daher läuft die Schleife so lange, bis die `break`-Anweisung erreicht wird.\n", "\n", - "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.\n", + "Bei jedem Durchlauf wird die Nutzer_in aufgefordert, etwas einzugeben. Wenn Sie `fertig` eingibt, dann beendet die `break`-Anweisung die Schleife. Ansonsten gibt das Programm einfach nur aus, was die Nutzer_in eingegeben hat und geht zurück zum Anfang der Schleife. Probieren Sie es selbst einmal aus.\n", "\n", "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\")." ] @@ -515,7 +489,7 @@ "\n", "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 Ziffer mit 9 zu multiplizieren. Das ist ein Algorithmus!\n", "\n", - "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.\n", + "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 auf den vorherigen mittels einfacher und eindeutiger Regeln folgt.\n", "\n", "Algorithmen auszuführen ist langweilig aber sie zu entwerfen ist interessant, intellektuell herausfordernd und ein wesentlicher Teil der Informatik.\n", "\n", @@ -530,7 +504,7 @@ "\n", "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.\n", "\n", - "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.\n", + "Eine Möglichkeit die Zeit für das Debuggen zu reduzieren ist \"Debugging durch Halbieren\" (denken Sie an die 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.\n", "\n", "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, die den Zwischenwert ausgibt (oder etwas anderes, was einen prüfbare Auswirkung hat), hinzu und starten Sie das Programm.\n", "\n", @@ -551,7 +525,7 @@ "\n", "- Neuzuweisung: \n", "- Aktualisierung:\n", - "- Initialisierung:\n", + "- Initialisierung: Das Erstellen einer Variablen und die damit verbundene erste Zuweisung eines Wertes\n", "- inkrementieren:\n", "- dekrementieren:\n", "- Iteration:\n", @@ -623,6 +597,96 @@ "test_square_root()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "([2038](https://xkcd.com/607/), Randall Munroe)\n", + "\n", + "\n", + "\n", + "([Spoiler Alert](https://xkcd.com/109/), Randall Munroe)\n", + "\n", + "\n", + "1. Schreiben Sie den Kopf der Funktion, überlegen Sie welche Argumente der Funktion übergeben müssen.\n", + "2. Kopieren Sie, wie oben bereits erwähnt die Funktion. \n", + "3. Wenn Sie das Notebook aufmerksam gelesen haben, werden Sie sich an einige Verbesserungen erinnern, die wir vornehmen müssen. \n", + "4. Vor allem heißt das x und y mit der `abs()`-Funktion zu vergleichen, also zu schreiben `abs(x-y)<epsilon` wobei Sie einen Wert für epsilon wählen müssen, der klein genug ist. Fügen Sie diese Änderungen in Ihren Code ein.\n", + "5. Wählen Sie einen geeigneten Wert für x in Abhängigkeit von a. Da fast jeder Wert funktioniert, können Sie ihn frei wählen, sie müssen lediglich sicherstellen, dass x ungleich null ist.\n", + "6. Vergessen Sie nicht Ihre Funktion mit Werten zu testen, die Sie überprüfen können. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def mysqrt(a):\n", + " if a==1:\n", + " x=a\n", + " else:\n", + " x=a-1\n", + " \n", + " epsilon=0.00000000001\n", + " while True:\n", + " y=(x+a/x)/2\n", + " if abs(y-x) < epsilon:\n", + " break\n", + " x=y\n", + " return x\n", + " \n", + " \n", + "mysqrt(25)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wenn die von Ihnen geschriebene Funktion richtig funktiniert, können Sie an der gewünschten Vergleichstabelle arbeiten. Dazu können Sie folgendermaßen ansetzen:\n", + "\n", + "\n", + "1. Der Kopf der Funktion ist bereits gegeben, aber Sie können bereits den Tabellenkopf schreiben. Dafür schreiben Sie eine `print`-Anweisung für jede Zeile des Tabellenkopfs.\n", + "2. Als nächstes müssen Sie entscheiden ob Sie die Tabelle von oben ausgeben wollen, dann muss a die Werte 1 bis 9 annehmen - Sie brauchen eine Schleife - oder ob Sie die Tabelle für ein beliebiges a berechnen wollen, dann müssen Sie User-Input einrichten.\n", + "3. Wir planen für die Schleife, für diesen Fall können Sie eine `While` oder eine `For` Schleife verwenden. \n", + "4. Prüfen Sie zunächst ob beide Funktionen Werte zurückgeben. Dies ist für die Pythonfunktion der Fall, trifft es auch auf Ihre Funktion zu? Wenn nicht ergänzen Sie die `return`-Anweisung an geeigneter Stelle.\n", + "5. Weißen Sie die beiden Funktionen und damit ihre Rückgabewerte neuen Funktionen zu. \n", + "6. Berechnen Sie die Differenz zwischen `mysqrt()` und `math.sqrt()` und speichern Sie diese in einer neuen Variablen\n", + "7. Für ein nachvollziehbares `a` testen Sie jetzt einmal die 3 Ausgaben. \n", + "8. Fügen Sie die `print` Anweisung hinzu, die die einzelnen Tabellenzeilen ausgibt. \n", + "9. Vergessen Sie nicht den Wert für a bei jedem Schleifendurchlauf zu erhöhen. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "def test_square_root():\n", + " a=1.0\n", + " print('a mysqrt(a) math.sqrt(a) diff')\n", + " print('- --------- ------------ ----')\n", + " while a<10:\n", + " E= mysqrt(a)\n", + " M= math.sqrt(a)\n", + " if E<M:\n", + " diff=M-E\n", + " else:\n", + " diff=E-M\n", + " E=str(E)\n", + " M=str(M)\n", + " print(a,E,(18-len(E))*' ',M,(18-len(M))*' ',diff)\n", + " a=a+1\n", + "\n", + " \n", + "test_square_root()" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -678,6 +742,42 @@ "# Implementieren Sie hier die Funktion eval_loop" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "([Spoiler Alert](https://xkcd.com/109/), Randall Munroe)\n", + "\n", + "1. Schreiben Sie den Funktionskopf\n", + "2. Richten Sie die Nutzereingabe ein und weißen Sie diese einer Variablen zu, damit wir den Input weiter verwenden können. \n", + "3. Da der Nutzer mehrfach eine Eingabe machen soll, muss diese Zuweißung innerhalb einer Schleife stattfinden.\n", + "4. Überlegen Sie welche Schleife Sie verwenden müssen, was ist hier Ihre Abbruchbedingung? Ist Sie positiv oder negativ?\n", + "5. Wenn `fertig` eingegeben wird, soll der letzte berechnete Wert zurückgegeben werden, daher muss dieser in einer Variablen temporär gespeichert werden.\n", + "6. Wenn nicht `fertig` eingegeben wird, wird der neue Ausdruck evaluiert und der Wert der zuvor in der temporären Variablen gespeichert war überschrieben. \n", + "7. Vergessen Sie nicht, dass die temporäre Variable initialisiert werden muss, bevor wir sie zum Speichern von Werten verwenden können. \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def eval_loop():\n", + " Eval=0\n", + " while True:\n", + " line = input('> ')\n", + " if line == 'fertig':\n", + " return(Eval)\n", + " break\n", + " Eval=eval(line)\n", + " print(Eval)\n", + " print('Fertig!')\n", + " \n", + "eval_loop()" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -694,9 +794,74 @@ "\n", "(Eventuell ist die Formel [in der Original-Aufgabenstellung](http://greenteapress.com/thinkpython2/html/thinkpython2008.html#hevea_default541) besser zu lesen.)\n", "\n", - "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.\n", + "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.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "([Spoiler Alert](https://xkcd.com/109/), Randall Munroe)\n", + "\n", + "1. Auf den ersten Blick sieht diese Formel sehr überwältigend aus. Machen Sie sich keine Sorgen, wir können die Formel in ihre einzelnen Bestandteile aufsplitten und diese einzeln berechnen.\n", + "2. Wie Sie sehen können wird in der Formel zweimal eine Fakultät berechnet. Dafür können Sie die Funktion, die Sie in Seminar 6 geschrieben verwenden. \n", + "3. Berechnen Sie zuerst die Konstante vor dem Summenzeichen und speichern Sie den Wert in einer Variablen. In unserer Lösung wird diesè Variable `faktor` genannt. \n", + "4. Die `while`-Schleife ersetzt das Summenzeichen. Überlegen Sie sich wie Sie die Bedingung formulieren müssen. Die Abbruchbedingung ist `abs(term)<1e-15` \n", + "5. Das Summenzeichen berechnet Werte für k=0 aufwärts (unedlich anstrebend), also muss die Schleife k hochzählen. \n", + "6. Alles was hinter dem Summenzeichen steht wird in der Schleife berechnet.\n", + "7. In jedem Durchgang der Schleife werden Zähler (hier `num`) und Nenner (hier `den`) einzeln berechnet und je einer Variablen zugewiesen\n", + "8. Anschließend wird der Wert des Terms im aktuellen Schleifendurchlauf berechnet, indem die Konstante vor dem Summenzeichen mit dem Bruch hinter dem Summenzeichen multipliziert wird. \n", + "9. Dieser Wert wird in jedem Schleifendurchlauf auf das Gesamtergebnis addiert\n", + "10. Danach wird geprüft ob die Abbruchbedingung erfüllt ist. \n", + "11. Da diese Formel 1/$\\pi$ berechnet, muss 1/ergebnis gerechnet werden um $\\pi$ zu erhalten. \n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "\n", + "def fakultaet(n):\n", + " if not isinstance(n, int):\n", + " print('Die Fakultät ist nur für ganze Zahlen definiert.')\n", + " return None\n", + " elif n < 0:\n", + " print('Die Fakultät für negative ganze Zahlen ist nicht definiert.')\n", + " return None\n", + " elif n == 0:\n", + " return 1\n", + " else:\n", + " return n * fakultaet(n-1)\n", + "\n", + "def estimate_pi():\n", + " faktor = 2 * math.sqrt(2) / 9801 \n", + " ergebnis = 0\n", + " k = 0\n", + " while True:\n", + " num = fakultaet(4*k) * (1103 + 26390*k)\n", + " den = fakultaet(k)**4 * 396**(4*k)\n", + " term = faktor * num / den\n", + " ergebnis= ergebnis + term\n", + " if abs(term) < 1e-15:\n", + " break\n", + " k =k + 1\n", + " \n", + " fast_pi= 1/ ergebnis\n", + " return fast_pi\n", "\n", - "Lösung: http://thinkpython2.com/code/pi.py" + "print(estimate_pi())" ] }, { -- GitLab