computational analysis - math.uni-luebeck.de · programmiert man in java rekursiv, so hat man immer...
TRANSCRIPT
Computational AnalysisComputergestützte Mathematik am Beispiel Mathematica
Im Rahmen der Veranstaltung Analysis II im Sommersemster 2012
Ronny Bergmann
Institut für Mathematik, Universität zu Lübeck
zuletzt geändert 17. April 2013
Homepage: math.uni-luebeck.de/mitarbeiter/bergmann/comp-ana-ss13.php
� Anmelden an den Rechnern: Login: mathestudenten, Passwort: ********
Anmerkungen und Bedienung von Mathematica
� Statt vor der Abgabe: (1) Evaluation -> Quit Kernel -> Local. (2) Evaluation Evaluate Notebook
durchzuführen, kann auch statt (1) Quit[] verwendet werden.
� Bis auf einige kleine Fehler waren die Abgaben super.
� denkt dran, Variablennamen nicht für Funktionen zu verwenden
In[2]:= mywert = 4;
In[3]:= mywert@x_D := 8 x
SetDelayed::write : Tag Integer in 4@x_D is Protected. �
Out[3]= $Failed
� Denkt an := bei den Funktionsdefinitionen
� Funktionen immer mit Argument in [] - auch bei bekannten Funktionen wie Cosinus.
Funktionsname, die Mathematica bereits implementiert hat, beginnen mit einem großen
Buchstaben. Was also formell cos(3x) heißt, schreibt man in Mathematica Cos[3x].
Teil II: Funktionen, private Variablen, Kontrollstrukturen
und Rekursion
Motivationsbeispiel: Zwei verschiedene Arten zu Programmieren
Wir beginnen heute mal mit einem kleinen Experiment, dass die Vorteile von Mathematica darstellt.
Wir möchten folgendes berechnen:
Gegeben sei
d HnL = âi=1
n
âj=1
n
i*j , n Î N.
Wie bestimmt man den Wert von d für ein gegebenes n möglichst effizient?
In[4]:=
Aus Java kennt man bereits die For - Schleife, nur dass sie hier wieder wie eine Funktion
geschrieben wird, in der die Argumente mit , getrennt werden:
In[5]:= ? For
For@start, test, incr, bodyD executes start, then repeatedly evaluates body and incr until test fails to give True. �
Bereiche für lokale Variablen (die werden dann ebenso grün gesetzt) ermöglicht die Funktion
Module
In[6]:= ? Module
Module@8x, y, … <, exprD specifies that occurrences of the symbols x, y, … in expr should be treated as local.
Module@8x = x0, … <, exprD defines initial values for x, … . �
Damit können wir einmal – nach den Gedanken eines Informatikers – die oben genannte Summe
berechnen, denn das ist ja lediglich eine Ineinanderschachtelung zweier For-Schleifen:
In[7]:= doppelsumme@n_D := Module@8summe, i, j<,summe = 0;
For@i = 1, i £ n, i++,
For@j = 1, j £ n, j++,
summe += i * j;
D;D;Return@summeD;
D;
In[8]:= doppelsumme@1000D
Out[8]= 250500250000
Der Mathematiker kommt vielleicht auf die Idee, den Term vorher einmal zu vereinfachen, vor allem
kennt er aber (und ihr ja nun auch bald) die vielen Möglichkeiten von Mathematica, zum Beispiel
den ersten und vorletzten Ausdruck in der Hilfe
In[9]:= ? Sum
Sum@ f , 8i, imax<D evaluates the sum âi=1
imax
f .
Sum@ f , 8i, imin, imax<D starts with i = imin.
Sum@ f , 8i, imin, imax, di<D uses steps di.
Sum@ f , 8i, 8i1, i2, … <<D uses successive values i1, i2, … .
Sum@ f , 8i, imin, imax<, 8 j, jmin, jmax<, … D evaluates the multiple sum âi=imin
imax
âj= jmin
jmax
… f .
Sum@ f , iD gives the indefinite sum âi
f . �
In[10]:= doppelsumme2@n_D := Sum@ Sum@i * j, 8j, 1, n<D, 8i, 1, n<D
Oder noch kürzer
2 2-Funktionen.nb
In[11]:= doppelsumme3@n_D := Sum@i * j, 8j, 1, n<, 8i, 1, n<D
Und wir vergleichen einmal die Laufzeiten indem wir den Befehl Timing betrachten
In[12]:= ? Timing
Timing@exprD evaluates expr, and returns a list of the time in seconds used, together with the result obtained. �
In[13]:= Timing@doppelsumme@1000DD
Out[13]= 83.879936, 250500250000<
In[14]:= Timing@doppelsumme2@1000DD
Out[14]= 80.137774, 250500250000<
In[15]:= Timing@doppelsumme3@1000DD
Out[15]= 80.033694, 250500250000<
In[16]:= doppelsumme@nD
Out[16]= 0
In[17]:= doppelsumme3@nD
Out[17]=
1
4
n2 H1 + nL2
Und die schnellste Lösung?
weitere Kontrollstrukturen I – bekannt aus Java
In[20]:= ? If
If@condition, t, f D gives t if condition evaluates to True, and f if it evaluates to False.
If@condition, t, f , uD gives u if condition evaluates to neither True nor False. �
In[21]:= ? Do
Do@expr, 8imax<D evaluates expr imax times.
Do@expr, 8i, imax<D evaluates expr with the
variable i successively taking on the values 1 through imax Hin steps of 1L.Do@expr, 8i, imin, imax<D starts with i = imin.
Do@expr, 8i, imin, imax, di<D uses steps di.
Do@expr, 8i, 8i1, i2, … <<D uses the successive values i1, i2, … .
Do@expr, 8i, imin, imax<, 8 j, jmin, jmax<, … D evaluates expr looping over different values of j, etc. for each i. �
Wobei Do eine wirklich nette Eigenschaft mit sich bringt, wenn man mal die vorletzte Beschreibung
betrachtet, so können wir eine Menge definieren, indem wir einen Vektor bauen
2-Funktionen.nb 3
In[22]:= ? Table
Table@expr, 8imax<D generates a list of imax copies of expr.
Table@expr, 8i, imax<D generates a list of the values of expr when i runs from 1 to imax.
Table@expr, 8i, imin, imax<D starts with i = imin.
Table@expr, 8i, imin, imax, di<D uses steps di.
Table@expr, 8i, 8i1, i2, … <<D uses the successive values i1, i2, … .
Table@expr, 8i, imin, imax<, 8 j, jmin, jmax<, … D gives a nested list. The list associated with i is outermost. �
In[23]:= S = Table@Prime@nD, 8n, 1, 20<D
Out[23]= 82, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71<
Dabei funktioniert Table fast wie Do, nur dass es einen Vektor an Werten zurückgibt, in diesem Fall
die ersten 20 Primzahlen. Dann können wir mit Do etwas für alle Elemente aus S ausrechnen :
In[24]:= Do@Print@"Die Wurzel der Zahl ", x,
" ist ", Sqrt@xD, " Hnumerisch: ", N@Sqrt@xDD, "L."D;, 8x, S<
D
Die Wurzel der Zahl 2 ist 2 Hnumerisch: 1.41421L.
Die Wurzel der Zahl 3 ist 3 Hnumerisch: 1.73205L.
Die Wurzel der Zahl 5 ist 5 Hnumerisch: 2.23607L.
Die Wurzel der Zahl 7 ist 7 Hnumerisch: 2.64575L.
Die Wurzel der Zahl 11 ist 11 Hnumerisch: 3.31662L.
Die Wurzel der Zahl 13 ist 13 Hnumerisch: 3.60555L.
Die Wurzel der Zahl 17 ist 17 Hnumerisch: 4.12311L.
Die Wurzel der Zahl 19 ist 19 Hnumerisch: 4.3589L.
Die Wurzel der Zahl 23 ist 23 Hnumerisch: 4.79583L.
Die Wurzel der Zahl 29 ist 29 Hnumerisch: 5.38516L.
Die Wurzel der Zahl 31 ist 31 Hnumerisch: 5.56776L.
Die Wurzel der Zahl 37 ist 37 Hnumerisch: 6.08276L.
Die Wurzel der Zahl 41 ist 41 Hnumerisch: 6.40312L.
Die Wurzel der Zahl 43 ist 43 Hnumerisch: 6.55744L.
Die Wurzel der Zahl 47 ist 47 Hnumerisch: 6.85565L.
Die Wurzel der Zahl 53 ist 53 Hnumerisch: 7.28011L.
Die Wurzel der Zahl 59 ist 59 Hnumerisch: 7.68115L.
Die Wurzel der Zahl 61 ist 61 Hnumerisch: 7.81025L.
Die Wurzel der Zahl 67 ist 67 Hnumerisch: 8.18535L.
Die Wurzel der Zahl 71 ist 71 Hnumerisch: 8.42615L.
In[25]:= ? While
While@test, bodyD evaluates test, then body, repetitively, until test first fails to give True. �
weitere Kontrollstrukturen II – der funktionale Anteil von Mathematica
Programmiert man in Java rekursiv, so hat man immer eine If-Abfrage, ob man bereits am Ende
ist. Dies geht in Mathematica schöner. Beispiel: Die Fibonacci - Zahlen
4 2-Funktionen.nb
Programmiert man in Java rekursiv, so hat man immer eine If-Abfrage, ob man bereits am Ende
ist. Dies geht in Mathematica schöner. Beispiel: Die Fibonacci - Zahlen
In[26]:= Fib@n_D := Fib@n - 1D + Fib@n - 2D;Fib@0D := 0;
Fib@1D := 1;
Also lassen wir uns mal die ersten 13 Zahlen ausgeben
In[29]:= Table@Fib@nD, 8n, 0, 12<D
Out[29]= 80, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144<
Diese Art zu programmieren ist funktional , die Definition dieser Funktion folgt der Idee des „Pattern
Matching“ - zu deutsch : musterbasierte Suche. Es wird diejenige Definition der 3 obigen gewählt,
die „am besten“ übereinstimmt, hier also für 0 und 1 die zweite bzw. dritte Zeile, sonst (weil nichts
besser passt) die erste.
Was man sich für größere und komplizierte Funktionen angewöhnen sollte ist eine Beschreibung
der Funktion. Diese kann man angeben mit ::usage
In[30]:= Fib::usage = "Fib@nD gibt die n-te Zahl der Fibonacci-Folge zurück.";
Dann hat man eine eigene Hilfe geschrieben :
In[31]:= ? Fib
Fib@nD gibt die n-te Zahl der Fibonacci-Folge zurück.
In Mathematica lassen sich weitere Forderungen an die Eingabe definieren, indem man statt mit ;
mit /; die Definition beendet und dann einen aussagenlogischen Ausdruck angibt. Beispiel : Eine
Funktion, die nur für Primzahlen definiert ist.
In[32]:= ? PrimeQ
PrimeQ@exprD yields True if expr is a prime number, and yields False otherwise. �
In[33]:= H*Der Dritte Fall betrifft uns*L ? /;
patt �; test is a pattern which matches only if the evaluation of test yields True.
lhs :> rhs �; test represents a rule which applies only if the evaluation of test yields True.
lhs := rhs �; test is a definition to be used only if test yields True. �
In[34]:= NumPrime@x_D := Module@8i<,i = 1;
While@Prime@iD ¹ x,
i++D;Return@iD;
D �; HPrimeQ@xDL H*Beim Aufruf wird geprüft,
ob x eine Primzahl ist, nur dann wird die Funktion ausgeführt*L
In[35]:= NumPrime::usage = "Gibt die Nummer zurück,
die eine Primzahl in der Folge der Primzahlen einimmt.";
Dann gibt die Funktion einen Wert zurück, falls die Eingabe eine Primzahl ist :
In[36]:= NumPrime@17D
Out[36]= 7
Und ist für andere Zahlen nicht definiert, was so aussieht :
2-Funktionen.nb 5
In[37]:= NumPrime@8D
Out[37]= NumPrime@8D
Eine andere Möglichkeit eine Funktion zu definieren ist der Befehl Function. Hier wird eine reine
Funktion erzeugt, ohne dass sie einen Namen bekommt. So kann man beispielsweise eine Funktion
zurückgeben:
In[38]:= ? Function
Function@bodyD or body & is a pure function. The formal parameters are ð Hor ð1L, ð2, etc.
Function@x, bodyD is a pure function with a single formal parameter x.
Function@8x1, x2, … <, bodyD is a pure function with a list of formal parameters. �
In[39]:= generateFunction@a_, b_, c_D := Function@x, a * x^2 + b * x + cD
Erzeugt Funktionen, die eine Unbekannte haben und gibt diese zurück :
In[40]:= generateFunction@2, 2, 2D
Out[40]= FunctionAx$, 2 x$2
+ 2 x$ + 2E
Und man kann dort gleich einen Wert einsetzen oder sich das symbolisch anschauen, etwa
In[41]:= generateFunction@2, 2, 2D@4D
Out[41]= 42
In[42]:= generateFunction@2, 2, 2D@yD
Out[42]= 2 + 2 y + 2 y2
Oder selbst aus dem Ergebis eine Funktion erzeugen
In[43]:= g@x_D := generateFunction@2, 2, 2D@xD
In[44]:= g@4D
Out[44]= 42
Aufgaben
Wir beginnen mit den Aufgaben in dieser Veranstaltung, aber mailt mir bitte eure Ergebnisse an
[email protected] jeweils in Zweiergruppen mit Name/Matrikelnummer. Natürlich
gehe ich jetzt mit rum und helfe beim Bearbeiten.
Aufgabe 1
Schreibe die rekursive Funktion fakultaet[n], die n! berechnet. Und gebe 30! aus.
Aufgabe 2
Die Collatz-Folge ist definiert als:
Gegeben sei ein Startwert x0 = k. Dann ist
xn=
xn-1
2falls xn-1 gerade,
3 xn-1 + 1 falls xn-1 ungerade,für n Î N
Und sie endet, falls xn = 1. (denn danach würde eine sich immer wiederholende Folge
1,4,2,1,4,2,1,... ergeben).
Schreibe eine rekursive Funktion Collatz[k], welche die Collatz-Folge für einen Startwert k
zurückgibt.
Schreibe dafür eine rekursive Funktion CollatzRek[s], die an den Vektor s so lange Elemente
anfügt, bis der letzte Eintrag in s eine 1 ist. Starte in der Funktion Collatz[n] lediglich die Rekursion
mit einem geeigneten Vektor s.
Nützliche Befehle: Last für den Zugriff auf das letzte Element von s, Append zum Anfügen, sowie
EvenQ und OddQ für die Mustertests, beachte dabei, dass im ungeraden Fall zusätzlich dieses letzte
Element nicht 1 sein darf, denn dafür gibt es einen extra Fall.
Prüfe deine Funktion mit dem Startwert 7 und gib die Folge an.
Wie viele Folgenglieder haben die Folgen mit den Startwerten 1199,1200 und 1201 ?
6 2-Funktionen.nb
Die Collatz-Folge ist definiert als:
Gegeben sei ein Startwert x0 = k. Dann ist
xn=
xn-1
2falls xn-1 gerade,
3 xn-1 + 1 falls xn-1 ungerade,für n Î N
Und sie endet, falls xn = 1. (denn danach würde eine sich immer wiederholende Folge
1,4,2,1,4,2,1,... ergeben).
Schreibe eine rekursive Funktion Collatz[k], welche die Collatz-Folge für einen Startwert k
zurückgibt.
Schreibe dafür eine rekursive Funktion CollatzRek[s], die an den Vektor s so lange Elemente
anfügt, bis der letzte Eintrag in s eine 1 ist. Starte in der Funktion Collatz[n] lediglich die Rekursion
mit einem geeigneten Vektor s.
Nützliche Befehle: Last für den Zugriff auf das letzte Element von s, Append zum Anfügen, sowie
EvenQ und OddQ für die Mustertests, beachte dabei, dass im ungeraden Fall zusätzlich dieses letzte
Element nicht 1 sein darf, denn dafür gibt es einen extra Fall.
Prüfe deine Funktion mit dem Startwert 7 und gib die Folge an.
Wie viele Folgenglieder haben die Folgen mit den Startwerten 1199,1200 und 1201 ?
Tipps
Da Colatz[n] die Folge der Werte zurückgeben soll, muss in jedem Schritt ein Element angefügt
werden und wir beginnen mit, also wissen wir
In[45]:= Collatz@n_D := CollatzRek@8n<D
Wir stellen uns vor, wir haben schon einige Elemente angefügt, haben also die Situation, dass die
Funktion CollatzRek[s_] aufgerufen wird mit einer Menge S={n, m1,m2,m3,...mk}. Wobei das Ganze
entstanden ist nach den obigen Regeln, also m1 ist n/2 falls n gerade oder 3n+1 falls n ungerade
usw. Wir müssen zunächst also einen Nachfolger bestimmen, den wir anfügen.
Welche Fälle gibt es?
Für die letzten beiden Fälle (ha! verraten, es gibt wohl drei oder mehr) haben wir eine neue Menge
S, was ist mit dieser zu tun?
Tipps zu den Befehlen:
Für eine Menge gibt uns der Befehl Last das letzte Element (genau das wollen wir ja immer betra-
chten), Beispielsweise
In[46]:= Last@8Π, E, 1, 2, 4, 1, 2<D
Out[46]= 2
Append fügt ein Element an, wenn wir den Nachfolger also bestimmt haben, hilft uns Append
In[47]:= Append@87, 22<, 11D
Out[47]= 87, 22, 11<
Naja und EvenQ[] und OddQ[] sind für die Abfragen in welchem der Fälle wir sind (wenn das letzte
Element nicht eh 1 ist)
In[48]:= a = 3;
If@EvenQ@aD, Print@"a ist gerade"D, Print@"a ist ungerade"DD
a ist ungerade
Aufgabe 3
Schreibe eine Funktion Taylor[n_, x0_, f_], die für eine univariate Funktion f(x) das n-te Taylor-
polynom als Funktion zurückgibt. Benutze dazu die Befehle Sum, Binomial, ! (Factorial) und D,
jedoch nicht Series.
Beachte dabei die Auswertungsreihenfolge (wie beim Integral brauchen wir also eventuell
Evaluate.)
1) Berechne zuerst die Summe
2) Baue eine implizite Funktion in x daraus und gebe dieses Ergebnis zurück.
Zusatzaufgabe: Gebe auch die Bedingungen an die Parameter an.
Gib dann die Taylorpolynome T4 und T5zu der Funktion f(x) = e2 x+Π
an der Stelle x0 = 0 an. Da Die
oben implementierte Funktion eine Funktion zurückgibt musst du natürlich noch einen symbolischen
Wert einsetzen, um das Polynom zu betrachten.
Zusatzaufgabe: Plotte beide Taylorpolynome zusammen mit f auf dem Intervall [-2,2]. Nutze dazu
den Befehl Plot und schau dir an, wie du mehrere Funktionen in einem Plot darstellen kannst.
2-Funktionen.nb 7
Schreibe eine Funktion Taylor[n_, x0_, f_], die für eine univariate Funktion f(x) das n-te Taylor-
polynom als Funktion zurückgibt. Benutze dazu die Befehle Sum, Binomial, ! (Factorial) und D,
jedoch nicht Series.
Beachte dabei die Auswertungsreihenfolge (wie beim Integral brauchen wir also eventuell
Evaluate.)
1) Berechne zuerst die Summe
2) Baue eine implizite Funktion in x daraus und gebe dieses Ergebnis zurück.
Zusatzaufgabe: Gebe auch die Bedingungen an die Parameter an.
Gib dann die Taylorpolynome T4 und T5zu der Funktion f(x) = e2 x+Π
an der Stelle x0 = 0 an. Da Die
oben implementierte Funktion eine Funktion zurückgibt musst du natürlich noch einen symbolischen
Wert einsetzen, um das Polynom zu betrachten.
Zusatzaufgabe: Plotte beide Taylorpolynome zusammen mit f auf dem Intervall [-2,2]. Nutze dazu
den Befehl Plot und schau dir an, wie du mehrere Funktionen in einem Plot darstellen kannst.
8 2-Funktionen.nb