Rheinisch-Westfälische Technische Hochschule Institut für Geometrie und Praktische Mathematik Mathematisches Praktikum (MaPra) — Sommersemester 2010 Prof. Dr. Wolfgang Dahmen — Dipl.-Math. Jens Berger, Dipl.-Math. Dipl.-Phys. Kolja Brix Zusatzaufgabe 1 für Informatiker Bearbeitungszeit: Mathematischer Hintergrund: Elemente von C++: drei Wochen (Abgabe bis Montag, den 17. Mai 2010) eindimensionale adaptive Quadratur, Quadraturformeln Rekursion, Einbinden einer Grakbibliothek, Makeles 10 Punkte Aufgabenstellung a, b ∈ R und eine Rb I(x) = a f (x) dx bis auf f : [a, b] → R. Schreiben Sie ein Programm, das das vorgegebenen Fehler ε berechnet. Benutzen Sie dazu eine adaptive Gegeben seien stetige Funktion Integral einen Unterteilung des Intervalls. Vergleichen Sie den Aufwand mit dem bei einer äquidistanten Unterteilung. Quadraturformeln Da Integrale nur in den wenigsten Fällen analytisch geschlossen berechenbar sind, bemüht man numerische Methoden zur Berechnung von Integralen (Quadratur ). Die eingesetzten Näherungsformeln werden als Qua- draturformeln bezeichnet. Dazu legt man für Funktion f 1≤i≤N Stützstellen xi mit a ≤ xi ≤ b fest, an denen die ausgewertet wird. In Abbildung 1 sind die drei einfachen Quadraturformeln Mittelpunktsregel, Trapezregel und Simpson-Regel dargestellt. Alle drei sind sogenannte Newton-Cotes-Formeln, die entstehen, indem man die Funktion f an den Stützstellen durch ein Polynom interpoliert und dieses anschlieÿend exakt integriert.[2] y y y f (x) a a+b 2 f (x) b x a (a) Mittelpunktsregel f (x) b x (b) Trapezregel a a+b 2 b x (c) Simpson-Regel Abbildung 1: Einfache Newton-Cotes-Quadraturformeln Die entstehenden Newton-Cotes-Formeln kann man dann in der allgemeinen Form von Quadraturformeln Z b f (x) dx ≈ (b − a) a N X i=1 1 γi f (xi ) schreiben, wobei die γi ∈ R die Gewichte der einzelnen Stützstellen bezeichnen. Tabelle 1 gibt die Stützstellen [a, b] wieder. und Gewichte der ersten Newton-Cotes-Quadraturformeln auf dem Intervall Quadraturformel Stützstellen xi Gewichte γi 1 a+b 2 Mittelpunktsregel a, b Trapezregel 1 1 2, 2 1 4 1 6, 6, 6 a, a+b 2 ,b Simpson-Regel Tabelle 1: Newton-Cotes-Quadraturformeln auf dem Intervall [a, b] Exaktheitsgrad und Ordnung Man klassiziert Quadraturformeln danach, bis zu welchem Grad sie Polynome exakt integrieren, d.h. bis zu m∈N welchem gilt Z b p(x) dx = (b − a) a wobei die Pm N X γi p(xi ), für alle p ∈ Pm , i=1 die Menge der Polynome vom Grad kleiner oder gleich Fall auch, die Quadraturformel ist exakt vom Grad m. m∈N bezeichnet. Man sagt in diesem Eine genauere Betrachtung ergibt, dass die Mittelpunktsregel und die Trapezregel exakt vom Grade 3.[2] Die Simpson-Regel ist sogar exakt vom Grade Hat die Quadraturformel die Exaktheitsgrad n und ist die Funktion (n + 1)-mal 1 sind. stetig dierenzierbar, so erhält man mit der Taylor-Entwicklung f (x) = n X f (k) (x0 ) k=0 k! (x − x0 )k + O((x − x0 )n+1 ). f durch ihr Taylor-Polynom. Da der Exaktheitsgrad der n beträgt, integriert sie das Taylor-Polynom exakt. Folglich hängt der Fehler der Quadratur des Integrationsintervalls in (n + 1)-ter Potenz ab, und damit hat die Quadraturformel die Nun ersetzt man bei der Quadratur die Funktion Quadraturformel von der Länge Ordnung n + 1. Summierte Quadraturformeln Zur Steigerung der Genauigkeit wendet man meist eine Quadraturformel nicht direkt auf das Intervall [a, b] an, sondern unterteilt es zunächst in Teilintervalle und wendet die Quadraturformel dann auf die Teilintervalle an. Auf diese Weise erhält man sogenannte summierte Quadraturformeln. [a, b] äquidistant in n Teilintervalle der Länge h := b−a n , so erhält ξj = a + jh mit ξ0 = a und ξn = b. Wendet man auf jedem Teilintervall Unterteilt man zum Beispiel das Intervall man für [ξj , ξj+1 ] 0≤j≤n die Stützstellen die Trapezregel IT (f, [ξj , ξj+1 ]) := 1 h (ξj+1 − ξj ) [f (ξj ) + f (ξj+1 )] = [f (ξj ) + f (ξj+1 )] 2 2 an, so erhält man die summierte Trapezregel ITn (f, [a, b]) := n X IT (f, [a + jh, a + (j + 1)h]) j=0 = n X h j=0 2 f (ξj ) + n−1 X h h h f (ξj+1 ) = f (a) + h f (a + jh) + f (b). 2 2 2 j=1 2 Adaptivität In vielen Fällen ist es zum Erreichen der gewünschten Genauigkeit des Integrals nicht notwendig, das gesamte Intervall in kleine Teilintervalle zu zerlegen. Verhält sich die Funktion f zum Beispiel auf einem groÿen Teilintervall wie eine Gerade, so wird sie hier bereits durch die Mittelpunktsregel exakt integriert. In einem anderen Abschnitt kann es jedoch nötig sein, das Intervall in viele Teilintervalle zu unterteilen. Liegt eine Möglichkeit vor, den Fehler der aktuellen Näherung zu schätzen, so kann man die Unterteilung in Abhängigkeit der gegebenen Funktion während des Verfahrens entsprechend den Erfordernissen steuern. Diese Fähigkeit eines Verfahrens, sich selbst an das gegebene Problem anzupassen, wird als Adaptivität bezeichnet. Einschluss der Lösung bei konvexen oder konkaven Funktionen Ist die gegebene Funktion auf dem Intervall [a, b] dierenzierbar und auÿerdem konvex oder konkav, so schlieÿen die durch die Mittelpunktsregel und Trapezregel numerisch bestimmten Näherungen des Integrals IM und IT den Wert des exakten Integrals I= Rb a f (x) dx ein, das heiÿt es ist min {IM , IT } ≤ I ≤ max {IM , IT } . f konkav auf dem Intervall [a, b] (sonst ist f konvex, −f , −IM und −IT ). Aufgrund der Konkavitätsbedingung ist der Funktionswert der Sekanten s(x) im Intervall [a, b] immer kleiner oder gleich dem Funktionswert f (x) und damit ist I = R R f (x) dx ≥ s(x) dx = IT . Beweis: Ohne Beschränkung der Allgemeinheit sei und man betrachte dann y y A B f (x) f (x) a b x a (a) Trapezregel a+b 2 b x (b) Mittelpunktsregel Abbildung 2: Einschluss der Lösung bei konkaver Funktion Der Inhalt der Fläche unter der Tangenten t(x) Mittelpunktsregel berechneten, denn die Dreiecke f im Mittelpunkt des Intervalls entspricht der von der A und B in Abbildung 2(b) sind gleich gross. Auf- grund der Konkavitätsbedingung kann die Funktion jedoch nicht oberhalb der Tangenten liegen und es gilt I= R f (x) dx ≤ R t(x) dx = IM . Diese Tatsache kann man bei der konvexen oder konkaven Funktionen nutzen und |IM − IT | als Schätzung des Quadraturfehlers verwenden. In der Praxis fällt diese Schätzung aber eher pessimistisch aus. Wird die Funktion f bereits an den Stützstellen der Mittelpunkts- und der Trapezregel ausgewertet, so kann mittels der Simpson-Regel leicht die Approximation höheren Exaktheitsgrades bestimmt werden. 3 Umsetzung im Programm Für das Programm verfolgen wir folgende Strategie: Soll das Integral der Funktion einem absoluten Fehler von höchstens ε f im Intervall [a, b] mit berechnet werden, so wenden wir die Mittelpunkts- und Trapezregel an und berechnen den Fehlerschätzer. Ist die gewünschte Genauigkeit erreicht, so geben wir das mit der Simpson-Regel berechnete Ergebnis zurück. Wurde die Genauigkeit ε verfehlt, so wird das Intervall in zwei Teilintervalle gleicher Länge zerlegt und auf jedem Teilintervall das Verfahren erneut durchgeführt, wobei nun je die Genauigkeit ε 2 verlangt wird. Der Aufwand einer Quadratur wird oft in der Anzahl der Funktionsauswertungen gemessen. Da eine Funktionsauswertung sehr aufwändig sein kann, sollten Sie vermeiden, die Funktion f mehrmals an der gleichen Stelle auszuwerten. Um die Wirkung der Adaptivität zu beobachten, vergleichen Sie die Anzahl der benötigten Funktionsauswertungen mit der, die bei der Quadratur mit der summierten Trapezregel bei äquidistanter Schrittweite notwendig ist. Verwenden Sie dabei die minimale Schrittweite, die im adaptiven Algorithmus nötig ist. Rekursive Programmierung Benutzen Sie die Technik der rekursiven Programmierung zur Implementierung Ihres Programms. Diese soll anhand des folgenden Beispiels erläutert werden. Beispiel: Berechnung der Fakultät Im Zusammenhang mit kombinatorischen Überlegungen benötigt man gelegentlich zu einer natürlichen Zahl n ihre Fakultät n! := Πnk=1 k . unsigned int 2 8 } 10 } } f ∗= i ; return int n) { f =1; i f ( n>1) { for ( unsigned int 6 12 f a k u l t a e t ( unsigned unsigned int 4 Dies läÿt sich leicht mit Hilfe einer Schleife programmieren. i =2; i<=n;++ i ) { f; Andererseits gilt für die Fakultät die Beziehung (n+1)! = n!(n+1). Dies legt eine andere Art der Umsetzung in ein Programm nahe: unsigned int 2 i f ( n<=1) return } else return 4 6 8 } } f a k u l t a e t ( unsigned int n) { { 1; n ∗ f a k u l t a e t ( n − 1) ; Die Programmiertechnik, bei der eine Funktion sich selbst wieder aufruft, heiÿt rekursive Programmierung. Die Rekursionstiefe gibt dabei an, wie oft sich die Funktion selbst aufgerufen hat. Bei rekursiver Programmierung muÿ vom Programmierer sichergestellt werden, dass die Rekursionstiefe beschränkt bleibt, das heiÿt, dass nach endlicher Anzahl von Selbstaufrufen die Funktion endet, ohne sich wieder selbst aufzurufen. Anderenfalls liegt eine unterminierte Rekursion vor, die solange fortgesetzt wird, bis alle zur Verfügung stehenden Ressourcen (z.B. Speicher) belegt sind. 4 Funktionsauswertungen und Zielgenauigkeit Fragen Sie zu Beginn Ihres Programmes den Benutzer nach dem zu rechnenden Beispiel. Fangen Sie mögliche Fehler bei der Eingabe ab. Rufen Sie anschlieÿend die Routine void S t a r t ( int Bsp , double &a , double &b , double &e p s i l o n , bool G r a f i k=true , int Pause =300) ; auf, die Ihnen die Grenzen des Intervalls epsilon a und b sowie die gewünschte Zielgenauigkeit des Ergebnisses zurückgibt. Die optionale Grakausgabe können Sie mit Grafik aktivieren. Der Parameter Pause steuert die Ausgabegeschwindigkeit. Die zu integrierende Funktion können Sie anschlieÿend durch einen Aufruf der Funktion double f ( double x ) ; auswerten. Geben Sie am Ende ihres Programmes das Resultat Ihrer numerischen Quadratur durch einen Aufruf von bool E r g e b n i s ( double I ) ; zurück. Es wird dann mit dem Wert des exakten Integrals verglichen und Ihr Ergebnis bewertet. Verwendung von Makefiles Programme, die aus mehreren Dateien bestehen, werden meist nicht per Hand kompiliert, stattdessen wird üblicherweise der Befehl make verwendet. Die Ausführung dieses Befehls wird durch die Datei Makefile (bzw. makefile) gesteuert. In ihr stehen sowohl die Regeln (Befehlssequenzen), wie man beispielsweise testZ1.o aus testZ1.cpp erhält, als auch die Abhängigkeiten der verschiedenen Dateien. Die Befehlssequenz zur Erzeugung einer bestimmten Datei wird immer dann ausgeführt, wenn wenigstens eine der Dateien, von denen sie abhängt, jünger ist als sie selbst. Dies befreit den Programmierer von der Aufgabe, sich über die Reihenfolge der Kompilierung Gedanken zu machen, und vermeidet überüssiges Kompilieren von Dateien, die bereits auf dem neuesten Stand sind. Makefile zur Erzeugung des Testprogramms der aussehen (<Tab > steht für das Tab(ulator)-Zeichen): Das aktuellen Aufgabe könnte zum Beispiel wie folgt CC = g++ CFLAGS = −O2 −Wall LIBS = −L/ u s r /X11R6/ l i b −lGL − l p t h r e a d −lX11 −lm testZ1 : testZ1 . o <Tab > $ (CC) −o t e s t Z 1 t e s t Z 1 . o u n i t Z 1 . o IGL . o $ ( LIBS ) t e s t Z 1 . o : t e s t Z 1 . cpp <Tab > $ (CC) $ (CFLAGS) −c t e s t Z 1 . cpp clean : <Tab > rm t e s t Z 1 . o t e s t Z 1 Erstellen Sie ein Makefile, damit es auch Ihr Programm erzeugt. [1] Literatur [1] Dokumentation zu GNU Make. http://www.gnu.org/software/make/. [2] Dahmen, W. und A. Reusken: Numerische Mathematik für Ingenieure und Naturwissenschaftler. Springer Verlag, Heidelberg, 2. Auflage, 2008. 5