MN14: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Przykry (dyskusja | edycje)
Przykry (dyskusja | edycje)
Nie podano opisu zmian
Linia 1: Linia 1:
<!--
Konwertowane  z pliku LaTeX przez latex2mediawiki, zob. http://www.ii.uj.edu.pl/&nbsp;pawlik1/latex2mediawiki.php.
Niezb�dne rozszerzenia i modyfikacje oryginalnego latex2mediawiki
wprowadzi� przykry@mimuw.edu.pl
-->
=Całkowanie=
=Całkowanie=
{{powrot |Metody numeryczne | do strony głównej
przedmiotu <strong>Metody numeryczne</strong>}}


Zajmiemy się teraz zadaniem całkowania numerycznego.  
Zajmiemy się teraz zadaniem całkowania numerycznego.  
Linia 11: Linia 21:
<math>\displaystyle F</math> funkcji rzeczywistych określonych i całkowalnych w  
<math>\displaystyle F</math> funkcji rzeczywistych określonych i całkowalnych w  
sensie Riemanna na całym przedziale <math>\displaystyle [a,b]</math>.
sensie Riemanna na całym przedziale <math>\displaystyle [a,b]</math>.
Każdy, kto przeszedł przez [[Analiza_matematyczna_1/Wykład_14:_Całka_Riemanna_funkcji_jednej_zmiennej|kurs całkowania]] wie, że obliczanie całek rozumiane jako znalezienie elementarnego wzoru na funkcję pierwotną może być trudne, bardzo trudne, a nawet niewykonalne. Tymczasem zadanie <strong>przybliżonego</strong> wyznaczenia wartości całki daje się w dużej mierze zautomatyzować z całkiem dobrym skutkiem.
Obliczanie całek jest wymagane w bardzo wielu zadaniach inżynierskich i naukowych. Całki z funkcji (bardzo) wielu zmiennych (które na swój sposób są szczególnie trudne do obliczenia) znajdują ważne zastosowania w bankowości i finansach.


Będziemy zakładać, że mamy możliwość obliczania  
Będziemy zakładać, że mamy możliwość obliczania  
wartości funkcji <math>\displaystyle f</math>, a w niektórych przypadkach  
wartości funkcji <math>\displaystyle f</math>, a w niektórych przypadkach  
również jej pochodnych o ile istnieją. Dokładna  
również jej pochodnych, o ile istnieją. Dokładna  
całka <math>\displaystyle S(f)</math> będzie więc w ogólności przybliżana  
całka <math>\displaystyle S(f)</math> będzie więc w ogólności przybliżana  
wartością <math>\displaystyle A(f)</math>, która zależy tylko od wartości <math>\displaystyle f</math>  
wartością <math>\displaystyle A(f)</math>, która zależy tylko od wartości <math>\displaystyle f</math>  
i ewentualnie jej pochodnych w skończonej liczbie punktów.  
i ew. jej pochodnych w skończonej liczbie punktów.  


==Kwadratury==
==Kwadratury==
Linia 47: Linia 61:
od danej informacji o <math>\displaystyle f</math>, otrzymana w ten sposób wartość  
od danej informacji o <math>\displaystyle f</math>, otrzymana w ten sposób wartość  
też będzie zależeć tylko od tej informacji, a w  
też będzie zależeć tylko od tej informacji, a w  
konsekwencji funkcjonał wynikowy będzie takiej postaci,
konsekwencji funkcjonał wynikowy będzie postaci  
jak wyżej. Są to tzw. kwadratury interpolacyjne.  
ja wyżej. Są to tzw. kwadratury interpolacyjne.  


{{definicja|||
{{definicja|||
Linia 59: Linia 73:


gdzie <math>\displaystyle w_f</math> jest wielomianem interpolacyjnym funkcji <math>\displaystyle f</math>  
gdzie <math>\displaystyle w_f</math> jest wielomianem interpolacyjnym funkcji <math>\displaystyle f</math>  
stopnia co najwyżej <math>\displaystyle n</math> opartym na tych węzłach.  
stopnia co najwyżej <math>\displaystyle n</math>, opartym na tych węzłach.  
}}
}}


Linia 84: Linia 98:
Podamy teraz kilka przykładów.  
Podamy teraz kilka przykładów.  


\noindent
<strong>Kwadratura prostokątów</strong> jest oparta na jednym węźle
<strong>Kwadratura prostokątów</strong> jest oparta na jednym węźle
<math>\displaystyle x_0=(a+b)//2</math>,  
<math>\displaystyle x_0=(a+b)//2</math>,  
Linia 91: Linia 104:
</math></center>
</math></center>


\noindent
<strong>Kwadratura trapezów</strong> jest oparta na jednokrotnych  
<strong>Kwadratura trapezów</strong> jest oparta na jednokrotnych  
węzłach <math>\displaystyle x_0=a</math>, <math>\displaystyle x_1=b</math> i jest równa polu odpowiedniego  
węzłach <math>\displaystyle x_0=a</math>, <math>\displaystyle x_1=b</math> i jest równa polu odpowiedniego  
Linia 99: Linia 111:
</math></center>
</math></center>


\noindent
<strong>Kwadratura parabol (Simpsona)</strong> jest oparta na  
<strong>Kwadratura parabol (Simpsona)</strong> jest oparta na  
jednokrotnych węzłach <math>\displaystyle x_0=a</math>, <math>\displaystyle x_1=b</math>, <math>\displaystyle x_2=(a+b)//2</math>,  
jednokrotnych węzłach <math>\displaystyle x_0=a</math>, <math>\displaystyle x_1=b</math>, <math>\displaystyle x_2=(a+b)//2</math>,  
Linia 123: Linia 134:


{{twierdzenie|||
{{twierdzenie|||
  Niech <math>\displaystyle Q^I</math> będzie kwadraturą  
   
Niech <math>\displaystyle Q^I</math> będzie kwadraturą  
interpolacyjną opartą na (jednokrotnych lub wielokrotnych)  
interpolacyjną opartą na (jednokrotnych lub wielokrotnych)  
węzłach <math>\displaystyle x_i</math>, <math>\displaystyle 0\le i\le n</math>. Jeśli <math>\displaystyle f\in F^n_M([a,b])</math>, to  
węzłach <math>\displaystyle x_i</math>, <math>\displaystyle 0\le i\le n</math>. Jeśli <math>\displaystyle f\in F^n_M([a,b])</math> to  


<center><math>\displaystyle  
<center><math>\displaystyle  
Linia 131: Linia 143:
</math></center>
</math></center>


W klasie <math>\displaystyle F^n_M([a,b])</math> maksymalny błąd kwadratury <math>\displaystyle Q^I</math>   
W klasie <math>\displaystyle F^n_M([a,b])</math>, maksymalny błąd kwadratury <math>\displaystyle Q^I</math>   
wynosi  
wynosi  


Linia 140: Linia 152:
}}
}}


\noindent
''Dowód''\quad Korzystając ze znanego nam już wzoru na  
''Dowód''\quad Korzystając ze znanego nam już wzoru na  
błąd interpolacji wielomianowej z Lematu [[##leblint|Uzupelnic: leblint ]], mamy  
błąd interpolacji wielomianowej z Lematu [[##leblint|Uzupelnic: leblint ]], mamy  
Linia 189: Linia 200:


{{twierdzenie|||
{{twierdzenie|||
  (i) Jeśli <math>\displaystyle f\in C^{(2)}([a,b])</math>,
   
Jeśli <math>\displaystyle f\in C^{(2)}([a,b])</math>  
to dla kwadratury trapezów mamy  
to dla kwadratury trapezów mamy  


Linia 195: Linia 207:
</math></center>
</math></center>


(ii) Jeśli <math>\displaystyle f\in C^{(4)}([a,b])</math>, to dla kwadratury  
Jeśli <math>\displaystyle f\in C^{(4)}([a,b])</math> to dla kwadratury  
parabol mamy  
parabol mamy  


Linia 204: Linia 216:
}}
}}


\noindent
''Dowód''\quad (i) Ze wzoru ([[##blkwad|Uzupelnic: blkwad ]])  
''Dowód''\quad (i) Ze wzoru ([[##blkwad|Uzupelnic: blkwad ]])  


Linia 213: Linia 224:
wielomian <math>\displaystyle (x-a)(x-b)</math> przyjmuje jedynie wartości  
wielomian <math>\displaystyle (x-a)(x-b)</math> przyjmuje jedynie wartości  
nieujemne, można zastosować twierdzenie o wartości  
nieujemne, można zastosować twierdzenie o wartości  
średniej dla całki aby otrzymać  
średniej dla całki, aby otrzymać  


<center><math>\displaystyle \aligned S(f)\,-\,T(f) &= f(a,b,c)\int_a^b (x-a)(x-b)\,dx \\
<center><math>\displaystyle \aligned S(f)\,-\,T(f) &= f(a,b,c)\int_a^b (x-a)(x-b)\,dx \\
Linia 221: Linia 232:
dla pewnych <math>\displaystyle c,\xi_1\in [a,b]</math>.
dla pewnych <math>\displaystyle c,\xi_1\in [a,b]</math>.


\noindent
(ii) Niech <math>\displaystyle w_{f,2}\in\Pi_2</math> i <math>\displaystyle w_{f,3}\in\Pi_3</math> będą  
(ii) Niech <math>\displaystyle w_{f,2}\in\Pi_2</math> i <math>\displaystyle w_{f,3}\in\Pi_3</math> będą  
wielomianami interpolacyjnymi funkcji <math>\displaystyle f</math> odpowiednio dla  
wielomianami interpolacyjnymi funkcji <math>\displaystyle f</math> odpowiednio dla  
Linia 296: Linia 306:


{{twierdzenie|||
{{twierdzenie|||
  Błąd kwadratury złożonej  
   
Błąd kwadratury złożonej  
<math>\displaystyle \bar Q(f)</math> w klasie <math>\displaystyle F^r_M([a,b])</math> jest ograniczony przez  
<math>\displaystyle \bar Q(f)</math> w klasie <math>\displaystyle F^r_M([a,b])</math> jest ograniczony przez  


Linia 311: Linia 322:
}}
}}


\noindent
''Dowód''\quad Twierdzenie to jest bezpośrednim  
''Dowód''\quad Twierdzenie to jest bezpośrednim  
wnioskiem z Twierdzenia [[##twblkw|Uzupelnic: twblkw ]]. Mamy bowiem  
wnioskiem z Twierdzenia [[##twblkw|Uzupelnic: twblkw ]]. Mamy bowiem  
Linia 324: Linia 334:
co kończy dowód. <math>\displaystyle \quad\Box</math>  
co kończy dowód. <math>\displaystyle \quad\Box</math>  


W klasie <math>\displaystyle F^r_M([a,b])</math> błąd kwadratur złożonych  
W klasie <math>\displaystyle F^r_M([a,b])</math>, błąd kwadratur złożonych  
jest rzędu <math>\displaystyle n^{-(r+1)}</math>, czyli jest taki sam jak  
jest rzędu <math>\displaystyle n^{-(r+1)}</math>, czyli jest taki sam jak  
błąd interpolacji kawałkami wielomianowej. I tak  
błąd interpolacji kawałkami wielomianowej. I tak  
Linia 353: Linia 363:


{{twierdzenie|||
{{twierdzenie|||
* Jeśli <math>\displaystyle f\in C^{(2)}([a,b])</math>, to   
Jeśli <math>\displaystyle f\in C^{(2)}([a,b])</math> to   


<center><math>\displaystyle S(f)\,-\,\bar T_k(f)\,=\,-\frac{(b-a)^2}{12\,k^2}
<center><math>\displaystyle S(f)\,-\,\bar T_k(f)\,=\,-\frac{(b-a)^2}{12\,k^2}
       f^{(2)}(\xi_1).
       f^{(2)}(\xi_1).
</math></center>
</math></center>
* Jeśli <math>\displaystyle f\in C^{(4)}([a,b])</math>, to  
 
Jeśli <math>\displaystyle f\in C^{(4)}([a,b])</math> to  


<center><math>\displaystyle S(f)\,-\,\bar P_k(f)\,=\,-\frac{(b-a)^4}{2280\,k^4}
<center><math>\displaystyle S(f)\,-\,\bar P_k(f)\,=\,-\frac{(b-a)^4}{2280\,k^4}
Linia 413: Linia 424:
pożądaną dokładność, zob. U. [[##kwas|Uzupelnic: kwas ]].  
pożądaną dokładność, zob. U. [[##kwas|Uzupelnic: kwas ]].  


Jeśli funkcja jest więcej niż dwa razy różniczkowalna,
Jeśli funkcja jest więcej niż dwa razy różniczkowalna  
użycie złożonych kwadratur trapezów zdaje się tracić  
to użycie złożonych kwadratur trapezów zdaje się tracić  
sens. Wtedy istnieją przecież kwadratury, których błąd  
sens. Wtedy istnieją przecież kwadratury, których błąd  
maleje do zera szybciej niż <math>\displaystyle n^{-2}</math>. Okazuje się jednak,  
maleje do zera szybciej niż <math>\displaystyle n^{-2}</math>. Okazuje się jednak,  
Linia 424: Linia 435:
[[grafika:Euler.jpg|thumb|right||Leonhard Euler<br>  [[Biografia Euler|Zobacz biografię]]]]
[[grafika:Euler.jpg|thumb|right||Leonhard Euler<br>  [[Biografia Euler|Zobacz biografię]]]]


[[grafika:Maclaurin.jpg|thumb|right|| Maclaurin<br>  [[Biografia MacLaurin|Zobacz biografię]]]]
[[grafika:Maclaurin.jpg|thumb|right||Colin Maclaurin<br>  [[Biografia Maclaurin|Zobacz biografię]]]]


{{lemat|Formuła Eulera-Maclaurina||
{{lemat|Formuła Eulera-Maclaurina|Formuła Eulera-Maclaurina|


Dla funkcji <math>\displaystyle f\in C^{(2m+2)}([a,b])</math> błąd złożonej  
Dla funkcji <math>\displaystyle f\in C^{(2m+2)}([a,b])</math>, błąd złożonej  
kwadratury trapezów <math>\displaystyle \bar T_k</math> wyraża się wzorem  
kwadratury trapezów <math>\displaystyle \bar T_k</math> wyraża się wzorem  


Linia 485: Linia 496:


Wtedy, dla <math>\displaystyle f\in F^{2m+1}_M([a,b])</math>, rząd zbieżności  
Wtedy, dla <math>\displaystyle f\in F^{2m+1}_M([a,b])</math>, rząd zbieżności  
kwadratury <math>\displaystyle \bar T^m_k</math> wynosi <math>\displaystyle k^{-(2m+2)}</math>. Rzeczywiście  
kwadratury <math>\displaystyle \bar T^m_k</math> wynosi <math>\displaystyle k^{-(2m+2)}</math>. Rzeczywiście,
sprawdziliśmy, że jest to prawdą dla <math>\displaystyle m=0,1</math>. Niech <math>\displaystyle m\ge 2</math>.  
sprawdziliśmy, że jest to prawdą dla <math>\displaystyle m=0,1</math>. Niech <math>\displaystyle m\ge 2</math>.  
Postępując indukcyjnie ze względu na <math>\displaystyle s=1,2,\ldots,m</math> mamy  
Postępując indukcyjnie ze względu na <math>\displaystyle s=1,2,\ldots,m</math> mamy  
Linia 519: Linia 530:
Zauważmy jeszcze, że <math>\displaystyle \bar T^m_k</math> wykorzystuje  
Zauważmy jeszcze, że <math>\displaystyle \bar T^m_k</math> wykorzystuje  
<math>\displaystyle n=k2^m+1</math> wartości <math>\displaystyle f</math> w punktach równoodległych  
<math>\displaystyle n=k2^m+1</math> wartości <math>\displaystyle f</math> w punktach równoodległych  
na <math>\displaystyle [a,b]</math>, co oznacza, że w terminach <math>\displaystyle n</math> rząd  
na <math>\displaystyle [a,b]</math> co oznacza, że w terminach <math>\displaystyle n</math> rząd  
zbieżności wynosi też <math>\displaystyle n^{-(2m+2)}</math>, a więc jest  
zbieżności wynosi też <math>\displaystyle n^{-(2m+2)}</math>, a więc jest  
optymalny w klasie <math>\displaystyle F^{2m+1}_M([a,b])</math>.
optymalny w klasie <math>\displaystyle F^{2m+1}_M([a,b])</math>.


Kwadratury <math>\displaystyle \bar T^s_k</math> nazywane są <strong>kwadraturami  
Kwadratury <math>\displaystyle \bar T^s_k</math> nazywane są <strong>kwadraturami  
Romberga</strong>. Dla danej funkcji <math>\displaystyle f</math> można je łatwo  
Romberga</strong>. Dla danej funkcji <math>\displaystyle f</math>, można je łatwo  
konstruować budując następującą tablicę trójkątną:  
konstruować budując następującą tablicę trójkątną:  


Linia 543: Linia 554:
w której pierwsza kolumna jest tworzona indukcyjnie  
w której pierwsza kolumna jest tworzona indukcyjnie  
zgodnie ze wzorem ([[##indtrap|Uzupelnic: indtrap ]]), a kolejne zgodnie  
zgodnie ze wzorem ([[##indtrap|Uzupelnic: indtrap ]]), a kolejne zgodnie  
z ([[##indRom|Uzupelnic: indRom ]]).
z ([[##indRom|Uzupelnic: indRom ]]).  


==Biblioteki==
==Biblioteki==
Linia 558: Linia 569:
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<div style="margin-top:1em; padding-top,padding-bottom:1em;">
<span  style="font-variant:small-caps;">Przykład: Prosta całka funkcji jednej zmiennej</span>  
<span  style="font-variant:small-caps;">Przykład: Prosta całka funkcji jednej zmiennej</span>  
<div class="solution">
<div class="solution" style="margin-left,margin-right:3em;">


Przypuśćmy, że chcemy obliczyć całkę <math>\displaystyle I = \int_0^1 F(x)\, dx</math>,
Przypuśćmy, że chcemy obliczyć całkę <math>\displaystyle I = \int_0^1 F(x)\, dx</math>,
Linia 564: Linia 575:
implementujemy <math>\displaystyle F</math> w Octave:  
implementujemy <math>\displaystyle F</math> w Octave:  


<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>function y = F(x)
function y = F(x)
y = sin(23*x)+1/sqrt(1-x^2);
y = sin(23*x)+1/sqrt(1-x^2);
endfunction
endfunction
</pre></div>
</pre></div>  
   
   
Aby teraz obliczyć całkę <math>\displaystyle I = \int_0^1 F(x)\, dx</math>, wystarczy wywołać
Aby teraz obliczyć całkę <math>\displaystyle I = \int_0^1 F(x)\, dx</math>, wystarczy wywołać


<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>I = quad("F", 0, 1);
</pre></div>  
I = quad("F", 0, 1);
</pre></div>
   
   
</div></div>
</div></div>


W rzeczywistości, podobnie jak w przypadku funkcji <code>fsolve</code>, funkcja
W rzeczywistości, podobnie jak w przypadku funkcji <code style="color: #006">fsolve</code>, funkcja
<code>quad</code> zwraca więcej informacji, można jej także przekazać dodatkowe
<code style="color: #006">quad</code> zwraca więcej informacji, można jej także przekazać dodatkowe
parametry. I tak, jeśli chcemy ustawić poziom tolerancji błędu obliczenia
parametry. I tak, jeśli chcemy ustawić poziom tolerancji błędu obliczenia
całki:
całki:
Linia 592: Linia 599:
przekazując jej te parametry następująco:
przekazując jej te parametry następująco:


<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>quad("F", 0, 1, [1e-3, 1e-6]);
</pre></div>  
quad("F", 0, 1, [1e-3, 1e-6]);
</pre></div>
   
   
Musimy jednak pamiętać, by pojęcia tolerancji "błędu" nie traktować zbyt
Musimy jednak pamiętać, by pojęcia tolerancji "błędu" nie traktować zbyt
dosłownie: tym, co naprawdę kontroluje <code>quad</code> podczas wyznaczania
dosłownie: tym, co naprawdę kontroluje <code style="color: #006">quad</code> podczas wyznaczania
wartości całki, jest jedynie pewien <strong>estymator</strong> błędu,  dlatego wartość
wartości całki, jest jedynie pewien <strong>estymator</strong> błędu,  dlatego wartość
tolerancji należy zawsze wybierać w sposób konserwatywny, czyli z pewnym zapasem
tolerancji należy zawsze wybierać w sposób konserwatywny, czyli z pewnym zapasem
bezpieczeństwa, np.
bezpieczeństwa, np.


<blockquote  style="background-color:#fefeee">  Jeśli chcemy wyznaczyć wartość całki z błędem bezwzględnym na
<blockquote  style="background-color: #fefeee; padding:1em;  margin-left,margin-right:2em;  margin-top,margin-bottom: 1em;">  Jeśli chcemy wyznaczyć wartość całki z błędem bezwzględnym na
poziomie <math>\displaystyle 10^{-6}</math>, ustawimy -- na wszelki wypadek --  
poziomie <math>\displaystyle 10^{-6}</math>, ustawimy -- na wszelki wypadek --  
<code>ATOL = 1e-7</code>, a nie, prostodusznie,
<code style="color: #006">ATOL = 1e-7</code>, a nie, prostodusznie,
<code>ATOL = 1e-6</code>... Musimy także pamiętać, że  choć są bardzo mało
<code style="color: #006">ATOL = 1e-6</code>... Musimy także pamiętać, że  choć są bardzo mało
prawdopodobne do spotkania w praktyce, to jednak istnieją <strong>wyuzdane</strong>
prawdopodobne do spotkania w praktyce, to jednak istnieją <strong>wyuzdane</strong>
funkcje, dla których estymator błędu może dać całkowicie fałszywe wartości,
funkcje, dla których estymator błędu może dać całkowicie fałszywe wartości,
przez co i obliczona całka może być obarczona dowolnie wielkim błędem.</blockquote>  
przez co i obliczona całka może być obarczona dowolnie wielkim błędem.</blockquote>  


Dodajmy, że <code>quad</code> doskonale radzi sobie także z funkcjami z osobliwościami (o
Dodajmy, że <code style="color: #006">quad</code> doskonale radzi sobie także z funkcjami z osobliwościami (o
ile tylko ją o nich uprzedzimy). Przykładowo, scałkujmy funkcję ze złośliwą nieciągłością w
ile tylko ją o nich uprzedzimy). Przykładowo, scałkujmy funkcję ze złośliwą nieciągłością w
zerze:
zerze:
Linia 620: Linia 625:
</math></center>
</math></center>


Oczywiście <math>\displaystyle \int_{-1}^1 f(x)\, dx = 0</math>, tymczasem definiując
Oczywiście, <math>\displaystyle \int_{-1}^1 f(x)\, dx = 0</math>, tymczasem definiując
<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #006; background-color:#fcfcfc;"><pre>function y = osobliwa(x)
function y = osobliwa(x)
if (x != 0.0)
if (x != 0.0)
y = 1/x;
y = 1/x;
Linia 632: Linia 635:


quad("osobliwa", -1, 1)
quad("osobliwa", -1, 1)
</pre></div>
</pre></div>  
   
   
daje w rezultacie
daje w rezultacie


<div class="output" style="background-color:#e0e8e8; padding:1em"><pre>
<div style="font-family: monospace; white-space: pre; border-style: dashed; border-width: thin; border-color: black; margin: 1em; padding:1em; color: #444; background-color:#fdfdfd;"><nowiki>ABNORMAL RETURN FROM DQAGP
ABNORMAL RETURN FROM DQAGP
ans = -81.098
ans = -81.098
</pre></div>
</nowiki></div>
   
   
-- błędny wynik i (na szczęście!) także komunikat o jakichś problemach procedury
-- błędny wynik i (na szczęście!) także komunikat o jakichś problemach procedury
całkującej. Jeśli jednak wspomożemy <code>quad</code> informacją o tym, że w <math>\displaystyle x=0</math> czai
całkującej. Jeśli jednak wspomożemy <code style="color: #006">quad</code> informacją o tym, że w <math>\displaystyle x=0</math> czai
się osobliwość, wszystko przebiegnie już gładko:
się osobliwość, wszystko przebiegnie już gładko:


<div class="output" style="background-color:#e0e8e8; padding:1em"><pre>
<div style="font-family: monospace; white-space: pre; border-style: dashed; border-width: thin; border-color: black; margin: 1em; padding:1em; color: #444; background-color:#fdfdfd;"><nowiki>quad("osobliwa", -1, 1, [1e-8 1e-8], 0)
quad("osobliwa", -1, 1, [1e-8 1e-8], 0)
ans = 0
ans = 0
</pre></div>
</nowiki></div>
   
   
(<code>1e-8</code> jest żądaną tolerancją błędu, równą wartości domyślnej).
(<code style="color: #006">1e-8</code> jest żądaną tolerancją błędu, równą wartości domyślnej).


====QUADPACK====
===QUADPACK===


Właściwie jedynym klasycznym pakietem, jaki mamy do dyspozycji jest
Właściwie jedynym klasycznym pakietem, jaki mamy do dyspozycji jest
Linia 660: Linia 659:
Jest to zestaw kilkunastu procedur fortranowskich, służących obliczaniu typowych całek
Jest to zestaw kilkunastu procedur fortranowskich, służących obliczaniu typowych całek
jednowymiarowych, w tym kilka ogólnego stosowania:
jednowymiarowych, w tym kilka ogólnego stosowania:
\begintable [ht]


{| border=1
{| border=1
|+ <span style="font-variant:small-caps"> </span>
|+ <span style="font-variant:small-caps"> </span>
|-  
|-  
|  
| Typ całki  ||  Procedura QUADPACKa
 
Typ całki  ||  Procedura QUADPACKa
|-
|-
|  
|  <math>\displaystyle \int_a^b f(x)</math>  ||  DQNG, DQAG, DQAGS, DQAGP  
   <math>\displaystyle \int_a^b f(x)</math>  ||  DQNG, DQAG, DQAGS, DQAGP  
|-
|-
|  
| <math>\displaystyle \int_{-\infty}^{\infty} f(x)</math>  ||  DQAGI  
<math>\displaystyle \int_{-\infty}^{\infty} f(x)</math>  ||  DQAGI  
|-
|-
|  
| <math>\displaystyle \int_a^b f(x)\cos(\omega x)</math>  ||  DQAWO  
<math>\displaystyle \int_a^b f(x)\cos(\omega x)</math>  ||  DQAWO  
|-
|-
|  
| <math>\displaystyle \int_a^b \dfrac{f(x)}{x-c}</math>  ||  DQAWC  
<math>\displaystyle \int_a^b \dfrac{f(x)}{x-c}</math>  ||  DQAWC  
|-
|-
|  
|  


|}
|}
\caption{Tabela najważniejszych procedur QUADPACKa i ich zastosowań.}
\endtable


oraz spora liczba podstawowych kwadratur, na których oparto te ogólne. Nazwy
oraz spora liczba podstawowych kwadratur, na których oparto te ogólne. Nazwy
procedur rozszyfrowuje się podobnie jak nazwy procedur LAPACKa, zatem
procedur rozszyfrowuje się podobnie jak nazwy procedur LAPACKa, zatem
* przedrostek <code>D</code> w nazwie każdej  procedury wymienionej w
* przedrostek <code style="color: #903">D</code> w nazwie każdej  procedury wymienionej w tabeli (np. <code style="color: #903">DQAGI</code>) oznacza, że będzie działać na liczbach typu <code>double</code> (całkując funkcję <math>\displaystyle f</math> zwracającą wartości tego samego typu). Gdybyśmy chcieli użyć pojedynczej precyzji, użylibyśmy nazwy procedury <strong>bez przedrostka</strong>.  
Tabeli&nbsp;[[##table:quadpack|Uzupelnic: table:quadpack ]] (np. <code>DQAGI</code>) oznacza, że będzie działać na liczbach typu
* Kolejna litera, <code style="color: #903">Q</code>, oczywiście oznacza kwadraturę (''Quadrature'').  
<code>double</code> (całkując funkcję <math>\displaystyle f</math> zwracającą wartości tego samego typu).
* Trzecia litera ---  <code style="color: #903">A</code> lub  <code style="color: #903">N</code> oznacza, odpowiednio, kwadraturę adaptacyjną lub nieadaptacyjną. Jak wiadomo, w praktyce lepiej sprawdzają się kwadratury adaptacyjne, potrafiące w jakiejś mierze dostosować się do przebiegu funkcji podcałkowej. Kwadratury nieadaptacyjne nie mają tej własności, natomiast są tańsze, warto więc je stosować w szczególnych przypadkach, gdy wiemy ''a priori'', że adaptacja niewiele pomoże: np. do wolno zmiennych funkcji.
Gdybyśmy chcieli użyć pojedynczej precyzji, użylibyśmy nazwy procedury <strong>bez
* Pozostałe litery precyzują typ liczonej całki i zakres ingerencji użytkownika; <code style="color: #903">G</code> --- "zwykła" całka, bez wagi, <code style="color: #903">W</code> --- całka z wagą, <code style="color: #903">O</code> --- oscylacyjną, <code style="color: #903">C</code> --- wartość główna całki (tzw. całka Cauchy'ego), <code style="color: #903">I</code> --- przedział nieskończony, <code style="color: #903">S</code> --- możliwe osobliwości, <code style="color: #903">P</code> --- użytkownik poda listę punktów, gdzie są osobliwości.
przedrostka</strong>.  
* Kolejna litera, <code>Q</code>, oczywiście oznacza kwadraturę
===GSL===
(''Quadrature '').  
* Trzecia litera - <code>A</code> lub  <code>N</code> - oznacza, odpowiednio,
kwadraturę adaptacyjną lub nieadaptacyjną. Jak wiadomo, w praktyce lepiej
sprawdzają się kwadratury adaptacyjne, potrafiące w jakiejś mierze dostosować
się do przebiegu funkcji podcałkowej. Kwadratury nieadaptacyjne nie mają tej
własności, są natomiast tańsze, warto więc je stosować w szczególnych
przypadkach, gdy wiemy a priori, że adaptacja niewiele pomoże: np. do
wolno zmiennych funkcji.
* Pozostałe litery precyzują typ liczonej całki i zakres ingerencji
użytkownika; <code>G</code> --- "zwykła" całka, bez wagi, <code>W</code> --- całka z
wagą, <code>O</code> --- oscylacyjną, <code>C</code> --- wartość główna całki (tzw. całka
Cauchy'ego), <code>I</code> --- przedział nieskończony, <code>S</code> --- możliwe
osobliwości, <code>P</code> --- użytkownik poda listę punktów, gdzie są osobliwości.
 
====GSL====


Biblioteka GSL reimplementuje podstawowe procedury QUADPACKa w języku C, zob.
Biblioteka GSL reimplementuje podstawowe procedury QUADPACKa w języku C, zob.
Linia 717: Linia 690:
szczegółowo opisane. Procedury GSL mają nazwy analogiczne, jak procedury
szczegółowo opisane. Procedury GSL mają nazwy analogiczne, jak procedury
QUADPACKa, ale z przedrostkiem <code>gsl_integration</code>, jak w poniższym
QUADPACKa, ale z przedrostkiem <code>gsl_integration</code>, jak w poniższym
przykładzie, gdzie  wywołamy odpowiednik procedury <code>DQAG</code>: funkcję
przykładzie, gdzie  wywołamy odpowiednik procedury <code style="color: #903">DQAG</code>: funkcję
<code>gsl_integration_qag</code>.
<code>gsl_integration_qag</code>.


<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
<div style="margin: 1em; padding:1em; color: #000; background-color:#fcfcfc;"><pre>#include <stdio.h>
#include <stdio.h>
#include <math.h>
#include <math.h>
#include <gsl/gsl_integration.h>
#include <gsl/gsl_integration.h>
Linia 759: Linia 731:
if (IER != 0)
if (IER != 0)
fprintf(stderr,"GSL_QAG: Kłopoty z całkowaniem\n");
fprintf(stderr,"GSL_QAG: Kłopoty z całkowaniem\n");
fprintf(stderr,"Całka:  
fprintf(stderr,"Całka: %g Est. błąd: %g IER: %d\n", RESULT, ABSERR,  IER);
 
gsl_integration_workspace_free(workspace);
gsl_integration_workspace_free(workspace);
Linia 772: Linia 745:


Miłym rozszerzeniem funkcjonalności jest możliwość
Miłym rozszerzeniem funkcjonalności jest możliwość
przekazywania parametrów do wnętrza funkcji podcałkowej.
przekazywania parametrów do wnętrza funkcji podcałkowej.  
=Różniczkowanie=


{{powrot |Metody numeryczne | do strony głównej
przedmiotu <strong>Metody numeryczne</strong>}}


=Numeryczne równania różniczkowe=
Z zadaniem numerycznego różniczkowania zadanej funkcji spotykamy się często w numeryce. Rzeczywiście, jeśli przypomnimy sobie metodę siecznych, to była to po prostu metoda Newtona, w której pochodną przybliżono pewnym ilorazem różnicowym:


Dla rozwiązywania równań różniczkowych zwyczajnych,  
<center><math>\displaystyle x_{k+1} = x_k - \frac{f(x_k)}{g_k},
</math></center>


<center><math>\displaystyle \aligned y'(t) &= f(y(t),t), \qquad t\in (t_0,T]\\
gdzie <center><math>\displaystyle g_k = \frac{f(x_k)-f(x_{k-1})}{x_k - x_{k-1}} \approx f'(x_k).</math></center>
y(t_0) &= y_0,
\endaligned</math></center>
Zauważmy, że nie jest to jedyny możliwy wzór na przybliżoną metodę Newtona, równie dobrze(? --- to się dopiero okaże!) moglibyśmy wziąć <center><math>\displaystyle g_k = \frac{f(x_k+h)-f(x_k)}{h}</math></center>
dla dostatecznie małego <math>\displaystyle h</math>.


korzystamy w Octave z funkcji <code>lsode</code>. Jak już zdążyliśmy się
Podobne formuły są także konieczne do konstrukcji metod numerycznego rozwiązywania równań różniczkowych, gdzie w naturalny sposób pojawia się konieczność operowania pochodną nieznanej funkcji.
przyzwyczaić, także ta funkcja jest jedynie zgrabnym interfejsem dla procedury
<code>DLSODE</code> z pakietu [http://www.netlib.org/odepack  ODEPACK] autorstwa
A.Hindmarscha. Domyślnie wybierana jest metoda BDF (dobra dla równań
trudniejszych, tzw. sztywnych równań różniczkowych, lecz względnie kosztowna).
Należy dodać, że ''solver ''kontroluje zachowanie się rozwiązania i sam w
trakcie obliczeń może zmienić wartości pewnych swoich parametrów w zależności od
bieżących potrzeb.


==Wprowadzenie do numerycznych metod rozwiązywania RRZ==
==Metody różnicowe==


LSODE jest pakietem, którego jądrem obliczeniowym są tzw. schematy różnicowe.
Rozważmy najprostszy sposób aproksymacji pochodnej <math>\displaystyle f'(x)</math>, oparty na <strong>różnicy dzielonej w przód</strong>, gdyż ze wzoru Taylora
Nie miejsce tu na dokładną analizę numeryczną metod rozwiązywania równań
różniczkowych zwyczajnych (zainteresowanych odsyłam do doskonałej monografii
Hairer et. al , bądź do
książki Palczewskiego), ograniczymy się tutaj do pewnych
intuicji. Będą nam one potrzebne, by móc świadomie wpływać na pewne parametry
metody w celu uzyskania lepszego (lub szybszego) rozwiązania (zazwyczaj te dwie
własności stoją w opozycji względem siebie).


====Jawne schematy różnicowe====
<center><math>\displaystyle f(x+h) = f(x) + f'(x)h  + O(h^2),
</math></center>


Najprostszym schematem aproksymacji równania różniczkowego zwyczajnego jest
pomijając człony rzędu <math>\displaystyle h^2</math>, dostajemy przybliżenie
schemat Eulera: gdy pochodną przybliżymy ilorazem różnicowym, dostajemy
(przybliżone) równanie


[[grafika:Euler.jpg|thumb|right||Leonhard Euler<br>  [[Biografia Euler|Zobacz biografię]]]]
<center><math>\displaystyle f'(x) \approx \frac{f(x+h)-f(x)}{h},
 
<center><math>\displaystyle  
\frac{y^h(t+h) - y^h(t)}{h} = f(y^h(t),t).
</math></center>
</math></center>


(dla podkreślenia, że spełniająca je funkcja jest jedynie przybliżeniem
a dokładniej,
dokładnego rozwiązania <math>\displaystyle y</math>, oznaczyliśmy je <math>\displaystyle y^h</math>).
Oznaczając dalej <math>\displaystyle t_1 = t_0+h</math>, <math>\displaystyle t_2 = t_1+h</math>, ... <math>\displaystyle t_n = t_{n-1}+h</math> zauważamy, że
z powyższej równości wynika wzór rekurencyjny
<center><math>\displaystyle \aligned
y_{n+1} - y_{n} = h\cdot f_n,
\endaligned</math></center>


gdzie <math>\displaystyle y_n = y^h(t_n) \approx y(t_n)</math> oraz <math>\displaystyle f_n = f(y_n,t_n)</math>. Naturalnie,
<center><math>\displaystyle f'(x) \frac{f(x+h)-f(x)}{h} + O(h).
warunkiem początkowym pozostaje <math>\displaystyle y_0</math>. Jest to schemat <strong>jawny</strong>, gdyż
</math></center>
<math>\displaystyle y_{n+1}</math> daje się wyznaczyć wprost z równania -- jest zadane w postaci
nieuwikłanej.


Uzasadnieniem dla schematu Eulera jest to, że iloraz <math>\displaystyle \frac{y_{n+1} -
Podobną dokładność aproksymacji dostaniemy, biorąc <strong>różnicę dzieloną w tył</strong>,
y_{n}}{h}</math> dość dobrze przybliża pochodną, gdy <math>\displaystyle h</math> jest małe:


<center><math>\displaystyle \frac{y_{n+1} - y_{n}}{h} = y'(t_n) + O(h).
<center><math>\displaystyle f'(x) = \frac{f(x)-f(x-h)}{h} + O(h).
</math></center>
</math></center>


Oczywiście pochodną <math>\displaystyle y'(t_n)</math> możemy przybliżać na różne sposoby, korzystając
Nietrudno przekonać się, że wzięcie średniej arytmetycznej tych dwóch aproksymacji daje tzw. <strong>różnicę centralną</strong>, która ma wyższy rząd aproksymacji, gdyż
np. z wielomianu interpolacyjnego dla <math>\displaystyle y</math>. Takie podejście prowadzi do klasy
<strong>metod wielokrokowych</strong>, ogólnej postaci


<center><math>\displaystyle \sum_{j=0}^k\alpha_k y_{n+k} = h \sum_{j=0}^k\beta_k f_{n+k},
<center><math>\displaystyle f'(x) = \frac{f(x+h)-f(x-h)}{2h} + O(h^2),
</math></center>
</math></center>


(metoda <math>\displaystyle k</math>-krokowa).
co znaczy, że dwukrotnie zmniejszając <math>\displaystyle h</math>, powinniśmy się spodziewać czterokrotnego zmniejszenia błędu aproksymacji pochodnej!
Inną ważną klasą metod są metody jednokrokowe tzw. <strong>Rungego--Kutty</strong>.


====Niejawne schematy różnicowe====
==Metody interpolacyjne==


Bardzo podobnie wyglądający <strong>niejawny schemat Eulera</strong>,
Jeśli chcemy uzyskać jeszcze wyższy rząd aproksymacji pochodnej, często jako wyrażenie aproksymujące przyjmuje się pochodną wielomianu interpolacyjnego.


<center><math>\displaystyle \aligned
Rzeczywiście, niech <math>\displaystyle w_n</math> będzie wielomianem interpolującym funkcję <math>\displaystyle f</math> w parami różnych węzłach <math>\displaystyle x_0< \cdots < x_n</math>, tzn.
y_{n+1} - y_{n} = h\cdot f_{n+1},
\endaligned</math></center>


ma znacząco różne własności. Pierwsza, która rzuca się w oczy to konieczność
<center><math>\displaystyle  
rozwiązywania równania nieliniowego na kazdym kroku schematu (co znacząco
w_n(x) = \sum_{i=0}^{n}f(x_i) l_i(x),
podnosi jego koszt), bo tym razem <math>\displaystyle y_{n+1}</math> zadaje się wzorem niejawnym:
</math></center>
<math>\displaystyle y_{n+1} - y_{n} = h\cdot f(y_{n+1},t_{n+1})</math>. Za chwilę pokażemy, że czasem
opłaca się zapłacić tę cenę, gdyż schematy niejawne mają pewne bardzo pożądane
własności.


====Lokalna dokładność schematu====
gdzie <math>\displaystyle l_i(x)</math> są \link{sec:interpol}{wielomianami bazowymi Lagrange'a}. Wtedy


Każdy schemat rozwiązywania
<center><math>\displaystyle  
równania zwyczajnego jest schematem przybliżonym, a jakość <strong>lokalnego</strong>
f'(x) \approx w_n'(x) = \sum_{i=0}^{n}f(x_i) l_i'(x),
przybliżenia równania schematem można ściśle określić przy użyciu wielkości
</math></center>
całkowitej zwanej  rzędem schematu: im wyższy, tym większa może być wartość
<math>\displaystyle h</math>, przy której schemat dostatecznie dobrze przybliżać będzie równanie.
Przykładowo, schemat Eulera stosunkowo mało dokładnie aproksymuje równanie dla
niezbyt małych <math>\displaystyle h</math>: aby uzyskać rozwiązanie obarczone możliwie małym błędem,
należy zazwyczaj wybierać dostatecznie mały <strong>krok schematu</strong> <math>\displaystyle h</math>, a to
znaczy, że w końcowym efekcie będziemy musieli wykonać bardzo wiele kroków
schematu, co podniesie jego całkowity koszt.
 
Należy pamiętać, że schematy wysokiego rzędu <strong>nie muszą</strong> prowadzić do
uzyskania dokładniejszego <strong>rozwiązania</strong>. Więcej szczegółów na ten temat
Czytelnik odnajdzie w fachowym monografiach, pamiętając, że metody użyte w
Octave potrafią do pewnego stopnia automatycznie dopasować krok całkowania i
rząd schematu tak, by uzyskać możliwie dobre przybliżenie prawdziwego
rozwiązania równania.


====Równania sztywne====
przy czym można wykazać, że


Schematy jawne okazują się niewystarczająco skuteczne dla pewnych ważnych klas
{{twierdzenie|O błędzie aproksymacji pochodnej za pomocą pochodnej wielomianu interpolacyjnego|O błędzie aproksymacji pochodnej za pomocą pochodnej wielomianu interpolacyjnego|
równań, tzw. równań sztywnych. Niektórzy autorzy wręcz definiują
równania sztywne jako te, dla których schematy jawne nie są skuteczne tzn. np.
schemat jawny z adaptacyjnym wyborem długości kroku musi stosować patologicznie
krótki krok.


Rozważmy sprawę sztywności na przykładzie układu równań różniczkowych liniowych
Niech <math>\displaystyle w_n</math> będzie wielomianem interpolującym funkcję <math>\displaystyle f\in C^{n+2}[a,b]</math> w równoodległych węzłach <math>\displaystyle a, a+h, a+2h, \ldots, b</math>, gdzie <math>\displaystyle h = (b-a)/n</math>. Wtedy zachodzi
<center><math>\displaystyle  
<center><math>\displaystyle 
\dfrac{dY}{dt} = - \Lambda Y
f'(x) - w_n'(x) = O(h^n) \quad \forall x\in [a,b]
</math></center>
</math></center>


(gdzie <math>\displaystyle Y(t) = (y_1(t),\ldots,y_K(t))^T\in R^K</math>, a <math>\displaystyle \Lambda</math> jest macierzą <math>\displaystyle K\times K</math>).
}}


Przypuśćmy, że macierz <math>\displaystyle \Lambda</math> jest diagonalizowalna,  a liczby <math>\displaystyle \lambda_1,\ldots,\lambda_K</math>
Wszystkie wprowadzone powyżej metody interpolacji oparte na wielomianie Taylora w rzeczywistości dadzą się sprowadzić do pochodnej wielomianu interpolacyjnego. Rzeczywiście,
są jej wartościami własnymi. Gdy wszystkie <math>\displaystyle \lambda_i</math> mają ujemne części
* różnica w przód to aproksymacja <math>\displaystyle f'(x)</math> pochodną wielomianu opartego na węzłach <math>\displaystyle x</math> i <math>\displaystyle x+h</math>,
rzeczywiste, składowe <math>\displaystyle y_i</math> rozwiązania gasną do zera, gdy <math>\displaystyle t\rightarrow
* różnica w tył to aproksymacja <math>\displaystyle f'(x)</math> pochodną wielomianu opartego na węzłach <math>\displaystyle x</math> i <math>\displaystyle x-h</math>,
\infty</math>. Rozsądne jest, aby od schematu wymagać podobnej właściwości, tzn. by
* różnica centralna to aproksymacja <math>\displaystyle f'(x)</math> pochodną wielomianu opartego na węzłach <math>\displaystyle x-h</math> i <math>\displaystyle x+h</math>; w tym ostatnim przypadku widzimy także, że powyższe twierdzenie nie zawsze jest ostre, bo dla różnicy centralnej byliśmy w stanie uzyskać wyższy niż minimalny gwarantowany przez twierdzenie rząd aproksymacji.
składowe <math>\displaystyle y^h_{i,n}</math> rozwiązania przybliżonego miały własność <math>\displaystyle y^h_{i,n}
   
\rightarrow 0</math>, gdy <math>\displaystyle n\rightarrow\infty</math>. Okazuje się, że  dla jawnej metody
Łatwo także --- korzystając z powyższego --- wyprowadzić nowe wzory na aproksymację, przykładowo,  
Eulera tak będzie, gdy


<center><math>\displaystyle  
<center><math>\displaystyle f'(x) = \frac{1}{2h} ( 3f(x) - 4f(x-h) + f(x-2h)) + O(h^2)
h \leq \dfrac{2}{\max_{i}\lambda_i}.
</math></center>
</math></center>


A więc długość kroku czasowego jawnej metody Eulera nie może być zbyt wielka,
korzysta tylko z wartości <math>\displaystyle f</math> na lewo od <math>\displaystyle x</math> (jest to więc ''różniczkowanie wstecz'') i też daje kwadratową aproksymację.
co jest szokujące, bo dla dużych wartości <math>\displaystyle t</math> rozwiązania stabilizują się
wokół zera i wydawać by się mogło, że to pozwoliłoby zwiększyć wówczas krok
schematu. Niestety tak nie jest i krok schematu musimy dostosować do
najmniejszej skali czasowej, która objawia się jedynie na początku ewolucji
układu. I to jest cecha charakterystyczna dla ogólnie nazywanych równań
sztywnych, nie tylko liniowych jak w powyższym przykładzie.


Tymczasem, dla niejawnego schematu Eulera nie ma w omawianym przykładzie
Analogicznie możemy aproksymować pochodne wyższych rzędów, np.
żadnego ograniczenia na krok schematu! Ogólniej, schematy niejawne, (czy to
wielokrokowe typu Adamsa--Bashfortha lub BDF, czy niejawne metody
Rungego--Kutty) lepiej nadają się do rozwiązywania równań sztywnych, niż
odpowiadające im analogiczne schematy jawne. Ceną, jaką płacimy za stosowanie
schematu niejawnego, a tym samym za uzyskanie mniejszych ograniczeń
stabilnościowych na długość użytego kroku schematu, jest większy (być może
nawet znacznie większy) koszt wykonania jednego kroku schematu, bo tym razem na
każdym kroku schematu musimy rozwiązywać równanie algebraiczne, w ogólnym
przypadku <strong>nieliniowe</strong>.  <code>lsode</code> domyślnie używa właśnie schematu
BDF, by użytkownik był z góry zabezpieczony na wypadek sztywności
rozwiązywanego zadania.


Niestety równania sztywne pojawiają się dość często w zastosowaniach, co
<center><math>\displaystyle f''(x) = \frac{f(x-h) - 2f(x) + f(x+h)}{h^2} + O(h^2).
generalnie wiąże się z obecnością różnych skal czasowych ewolucji
</math></center>
poszczególnych składników rozważanego modelu. Sztywne są m.in.
układy równań różniczkowych zwyczajnych powstałe po dyskretyzacji
(przestrzennej) równań różniczkowych cząstkowych typu parabolicznego. Również wiele układów równań różniczkowych
zwyczajnych spotykanych w zastosowaniach, np. w modelach reakcji chemicznych,
jest z natury sztywnych. Podkreślmy raz jeszcze, że z analizy teoretycznej i z
praktycznych doświadczeń wynika, że dla tej klasy zadań niezbędne jest
stosowanie <strong>schematów niejawnych</strong>, np. typu BDF, w których <math>\displaystyle y_{n+1}</math> będzie
zadane w sposób uwikłany.


==Biblioteki==
Tę formułę możemy znów uzyskać na wiele sposobów:
* wprost ze wzoru Taylora, raz dla <math>\displaystyle f(x+h)</math>, a raz dla <math>\displaystyle f(x-h)</math>,
* jako drugą pochodną wielomianu interpolacyjnego,
* jako złożenie różnicy dzielonej w przód z różnicą dzieloną w tył (co ma naśladować matematyczną zależność, że <math>\displaystyle f''(x) = (f'(x))'</math>.
Namawiamy czytelnika do sprawdzenia, że faktycznie powyższy wzór można tak wyprowadzić.


Działanie instrukcji Octave'a <code>lsode</code> najlepiej prześledzić na konkretnym
<!--
przykładzie.
===Różniczkowanie wielomianu algorytmem Hornera===


====Rozwiązujemy równanie Van der Pola====
Jak widać z powyższego, warto jest umieć rozwiązać następujące ogólne zagadnienie: mając zadany wielomian interpolacyjny, znaleźć jego pochodną w punkcie <math>\displaystyle x</math>. Okazuje się, że do tego znakomicie nadaje się [[|algorytm Hornera]].
 
-->
Rozważmy równanie różniczkowe zwyczajne rzędu drugiego, opisujące tak zwany
oscylator Van der Pola:
==Uwarunkowanie==
 
<center><math>\displaystyle \aligned
y'' + \epsilon (y^2-1)y' + y = 0.
\endaligned</math></center>


Ponieważ metody dla równań zwyczajnych zazwyczaj pisze się dla równań pierwszego
==Kłopoty numeryczne==
rzędu (i takie są procedury Octave), zapiszemy najpierw to równanie w
postaci układu równań pierwszego rzędu:


<center><math>\displaystyle \aligned y_1' &= y_2\\
Rozważmy przykładowo różnicę w przód dla <math>\displaystyle h>0</math>. Gdyby arytmetyka której używamy miała nieskończoną precyzję, to oczywiście zachodzi
y_2' &= - \epsilon (y_1^2 - 1) y_2 - y_1.
\endaligned</math></center>


Jest to równanie różniczkowe postaci
<center><math>\displaystyle \frac{f(x+h)-f(x)}{h} - f'(x) = O(h),
<center><math>\displaystyle  
y'(t) = f(y(t),t), \qquad t\in [t_0,T],
</math></center>
</math></center>


gdzie u nas <math>\displaystyle y</math> jest wektorem o dwóch współrzędnych, <math>\displaystyle y = (y_1,y_2)^T</math>.
i przybliżenie byłoby tym lepsze, im mniejsze byłoby <math>\displaystyle h</math>. Jednak w praktyce tak nie będzie, ze względu na fakt, że działamy w arytmetyce skończonej precyzji:
Aby znaleźć numeryczne rozwiązanie tego równania w Octave, najpierw zdefiniujemy
* dla małych <math>\displaystyle h</math>, mamy <math>\displaystyle f(x+h) -f(x) \approx 0</math>, a więc zachodzi duże ryzyko utraty cyfr przy odejmowaniu
M-funkcję, która oblicza prawą stronę <math>\displaystyle f(y,t)</math>:
* dla małych <math>\displaystyle h</math>, może zdarzyć się, że numerycznie <math>\displaystyle fl_\nu(x+h) = fl_\nu(x)</math> i w konsekwencji <math>\displaystyle fl_\nu(\frac{f(x+h)-f(x)}{h}) = 0</math>.
 
<div class="code" style="background-color:#e8e8e8; padding:1em"><pre>
   
   
function ydot = vanderpol(y,t)
Można więc postawić sobie pytanie, jak dobrać <math>\displaystyle h</math> na tyle małe, by mieć możliwie dobrą aproksymację <math>\displaystyle f'(x)</math>, a jeszcze nie odczuć zgubnych skutków wpływu arytmetyki zmiennoprzecinkowej. Formalnie, możemy pytanie postawić w sposób następujący:
global epsilon;


ydot = [y(2);
Przypuśćmy, że zamiast <math>\displaystyle f(x)</math> wyznaczane jest <math>\displaystyle \tilde{f}(x) = f(x)+\epsilon_x</math>, przy czym <math>\displaystyle |\epsilon_x| \leq \epsilon</math>. Jak dobrać do <math>\displaystyle \epsilon</math> parametr <math>\displaystyle h</math> w taki sposób, by aproksymacja <center><math>\displaystyle \frac{\tilde{f}(x+h)-\tilde{f}(x)}{h} \approx f'(x)</math></center>
        epsilon*(1-y(1)^2)*y(2) - y(1)];
była jak najlepsza?
endfunction
Mamy:
</pre></div>
Zwróćmy uwagę na wykorzystanie zmiennej <code>global</code>nej <code>epsilon</code>, dzięki której
będzie możliwe przekazanie wartości parametru <math>\displaystyle \epsilon</math> do wnętrza funkcji
<code>vanderpol(y,t)</code>. Procedura rozwiązująca równanie wymaga funkcji, której
argumentami są tylko i wyłącznie liczba <math>\displaystyle t</math> i wektor <math>\displaystyle y</math> o tylu współrzędnych
ile jest równań w układzie.


Choć trudno w to uwierzyć, to jednak w zasadzie najtrudniejszy krok mamy za
<center><math>\displaystyle \aligned \left| \frac{\tilde{f}(x+h)-\tilde{f}(x)}{h} - f'(x) \right| &= \left| \frac{1}{h}( (f(x+h)+\epsilon_{x+h}) - (f(x) + \epsilon_x)) - f'(x) \right| \\
sobą! Teraz, aby rozwiązać równanie, wystarczy wywołać funkcję
&\leq
\left| \frac{ f(x+h) - f(x)}{h} - f'(x)\right| + \frac{2\epsilon}{h}
\endaligned</math></center>


<code>lsode("vanderpol",y0,t)</code>,  
Ponieważ pierwszy człon wyrażenia daje się oszacować (dla dostatecznie regularnej funkcji <math>\displaystyle f</math>) przez <math>\displaystyle C\cdot h</math>, to ostatecznie dostajemy


gdzie <code>y0</code> będzie wektorem wartości początkowych rozwiązania: <math>\displaystyle y(t_0) =
<center><math>\displaystyle \left| \frac{\tilde{f}(x+h)-\tilde{f}(x)}{h} - f'(x) \right| \leq C_1(h + \frac{1}{h}).
y_0</math>, a wektor <code>t</code> - zestawem kolejnych punktów (pierwszym
</math></center>
punktem w zestawie musi być oczywiście chwila początkowa <math>\displaystyle t_0</math>) w przedziale czasowym
<math>\displaystyle [t_0,T]</math>, w których zechcemy poznać wartości rozwiązania: naturalnie, aby
dobrze przedstawić rozwiązanie graficznie, musimy wyznaczyć je w dostatecznie
wielu punktach.


====CVODE====
Wyrażenie po prawej stronie jest minimalizowane dla <math>\displaystyle h = \sqrt{\epsilon}</math> i stąd inżynierska reguła:


Z dobrych bibliotek napisanych w C należy wymienić pakiet
<blockquote  style="background-color: #fefeee; padding:1em;  margin-left,margin-right:2em;  margin-top,margin-bottom: 1em;"> 
[http://www.netlib.org/ode  CVODE]. Omówienie jego możliwości wykracza
Jeśli chcesz używać różnicy w przód, powinieneś wziąć <math>\displaystyle h</math> równe co najmniej <math>\displaystyle \sqrt{\epsilon_{ \mbox{mach} }}</math>.
jednak poza zakres niniejszego wykładu.
</blockquote>

Wersja z 21:53, 29 wrz 2006


Całkowanie

<<< Powrót do strony głównej przedmiotu Metody numeryczne

Zajmiemy się teraz zadaniem całkowania numerycznego. Polega ono na obliczeniu (a raczej przybliżeniu) całki oznaczonej

S(f)=abf(x)dx,

gdzie <a<b<+, a f należy do pewnej klasy F funkcji rzeczywistych określonych i całkowalnych w sensie Riemanna na całym przedziale [a,b].

Każdy, kto przeszedł przez kurs całkowania wie, że obliczanie całek rozumiane jako znalezienie elementarnego wzoru na funkcję pierwotną może być trudne, bardzo trudne, a nawet niewykonalne. Tymczasem zadanie przybliżonego wyznaczenia wartości całki daje się w dużej mierze zautomatyzować z całkiem dobrym skutkiem.

Obliczanie całek jest wymagane w bardzo wielu zadaniach inżynierskich i naukowych. Całki z funkcji (bardzo) wielu zmiennych (które na swój sposób są szczególnie trudne do obliczenia) znajdują ważne zastosowania w bankowości i finansach.

Będziemy zakładać, że mamy możliwość obliczania wartości funkcji f, a w niektórych przypadkach również jej pochodnych, o ile istnieją. Dokładna całka S(f) będzie więc w ogólności przybliżana wartością A(f), która zależy tylko od wartości f i ew. jej pochodnych w skończonej liczbie punktów.

Kwadratury

Kwadraturami nazywamy funkcjonały liniowe Parser nie mógł rozpoznać (nieznana funkcja „\toR”): {\displaystyle \displaystyle Q:F\toR} postaci

Q(f)=i=0naif(xi),

albo ogólniej

Q(f)=i=0kj=0ni1ai,jf(j)(xi),

gdzie xi są punktami z [a,b], a ai (albo ai,j) są pewnymi współczynnikami rzeczywistymi. Zauważmy, że obliczenia kwadratur są dopuszczalne w naszym modelu obliczeniowym, mogą więc służyć jako sposób przybliżania całki.

Jeden z możliwych sposobów konstrukcji kwadratur jest następujący. Najpierw wybieramy węzły xj (pojedyncze lub wielokrotne), budujemy wielomian interpolacyjny odpowiadający tym węzłom, a następnie całkujemy go. Ponieważ postać wielomianu interpolacyjnego zależy tylko od danej informacji o f, otrzymana w ten sposób wartość też będzie zależeć tylko od tej informacji, a w konsekwencji funkcjonał wynikowy będzie postaci ja wyżej. Są to tzw. kwadratury interpolacyjne.

Definicja

Kwadraturę QI opartą na węzłach o łącznej krotności n+1 nazywamy interpolacyjną, jeśli

QI(f)=abwf(x)dx,

gdzie wf jest wielomianem interpolacyjnym funkcji f stopnia co najwyżej n, opartym na tych węzłach.

Współczynniki kwadratur interpolacyjnych można łatwo wyliczyć. Rozpatrzmy dla uproszczenia przypadek, gdy węzły są jednokrotne. Zapisując wielomian interpolacyjny w postaci jego rozwinięcia w bazie kanonicznej Lagrange'a li (zob. (Uzupelnic: Lagrbaza )), otrzymujemy

QI(f)=abi=0nf(xi)li(x)dx=i=0nf(xi)abli(x)dx,

a stąd i z postaci li,

ai=ab(xx0)(xxi1)(xxi+1)(xxn)(xix0)(xixi1)(xixi+1)(xixn)dx,

0in.

Podamy teraz kilka przykładów.

Kwadratura prostokątów jest oparta na jednym węźle x0=(a+b)//2,

Q0I(f)=(ba)f(a+b2).

Kwadratura trapezów jest oparta na jednokrotnych węzłach x0=a, x1=b i jest równa polu odpowiedniego trapezu,

Q1I(f)=T(f)=ba2(f(a)+f(b)).

Kwadratura parabol (Simpsona) jest oparta na jednokrotnych węzłach x0=a, x1=b, x2=(a+b)//2, i jest równa polu pod parabolą interpolującą f w tych węzłach,

Q2I(f)=P(f)=ba6(f(a)+4f(a+b2)+f(b)).

Zauważmy, że kwadratury trapezów i parabol są oparte na węzłach jednokrotnych i równoodległych, przy czym x0=a i xn=b. Ogólnie, kwadratury interpolacyjne oparte na węzłach równoodległych Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle x_i=a+(b-a)i/ń} , 0in, nazywamy kwadraturami Newtona--Cotesa.

Błąd kwadratur interpolacyjnych

Zajmiemy się teraz błędem kwadratur interpolacyjnych. Przypomnijmy, że FMn([a,b]) oznacza klasę funkcji (n+1) razy różniczkowalnych w sposób ciągły i takich, że |f(n+1)(x)|M, x.

Twierdzenie

Niech QI będzie kwadraturą interpolacyjną opartą na (jednokrotnych lub wielokrotnych) węzłach xi, 0in. Jeśli fFMn([a,b]) to

|S(f)QI(f)|M(n+1)!(ba)n+2.

W klasie FMn([a,b]), maksymalny błąd kwadratury QI wynosi

supfFMn([a,b])|S(f)QI(f)|=M(n+1)!ab|(xx0)(xx1)(xxn)|dx.

Dowód\quad Korzystając ze znanego nam już wzoru na błąd interpolacji wielomianowej z Lematu Uzupelnic: leblint , mamy

S(f)QI(f)=ab(xx0)(xx1)(xxn)f(x0,x1,,xn,x)dx.

Stąd, jeśli fFMn([a,b]) to

|S(f)QI(f)|ab(ba)n+1M(n+1)!dx=(ba)n+2M(n+1)!.

Ograniczenie górne w dokładnej formule na błąd w klasie FMn([a,b]) wynika bezpośrednio z oszacowania (Uzupelnic: blkwad ). Aby pokazać ograniczenie dolne zauważmy, że dla funkcji g takiej, że g(n+1) przyjmuje na przedziałach (a,x0), (x0,x1), , (xn,b) naprzemiennie wartości M i M mamy

|S(g)QI(g)|=M(n+1)!ab|(xx0)(xx1)(xxn)|dx.

Co prawda, g nie jest w FMn[a,b], ale może być dla dowolnego ϵ>0 przybliżana funkcjami fϵFMn([a,b]) w ten sposób, że całka

ab|(xx0)(xxn)(fg)(n+1)(x)|dxϵ(n+1)!.

Zapisując fϵ=g+(fϵg) mamy

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned |S(f_\epsilon)\,-\,Q^I(f_\epsilon)| &\le & |S(g)\,-\,Q^I(g)|\,+\, |S(f_\epsilon-g)-Q^I(f_\epsilon-g)| \\ &\le & \frac M{(n+1)!}\int_a^b |(x-x_0)\cdots(x-x_n)| \,dx\,+\,\epsilon, \endaligned}

co wobec dowolności ϵ daje dowód twierdzenia.

W szczególnych przypadkach kwadratur trapezów T i parabol P możemy otrzymać innego rodzaju formuły na błąd.

Twierdzenie

Jeśli fC(2)([a,b]) to dla kwadratury trapezów mamy

S(f)T(f)=(ba)312f(2)(ξ1).

Jeśli fC(4)([a,b]) to dla kwadratury parabol mamy

S(f)P(f)=(ba)52280f(4)(ξ2).

(ξ1,ξ2[a,b]).

Dowód\quad (i) Ze wzoru (Uzupelnic: blkwad )

S(f)T(f)=ab(xa)(xb)f(a,b,x)dx.

Ponieważ funkcja xf(a,b,x) jest ciągła, a wielomian (xa)(xb) przyjmuje jedynie wartości nieujemne, można zastosować twierdzenie o wartości średniej dla całki, aby otrzymać

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned S(f)\,-\,T(f) &= f(a,b,c)\int_a^b (x-a)(x-b)\,dx \\ &= -\frac{f^{(2)}(\xi_1)}{2!}\frac{(b-a)^3}6, \endaligned}

dla pewnych c,ξ1[a,b].

(ii) Niech wf,2Π2 i wf,3Π3 będą wielomianami interpolacyjnymi funkcji f odpowiednio dla węzłów a,b,(a+b)//2 oraz a,b,(a+b)//2,(a+b)//2. Wtedy

wf,3(x)=wf,2(x)+f(a,b,a+b2,a+b2)(xa)(xa+b2)(xb).

Wobec

ab(xa)(a+b2)(xb)dx=0

mamy

P(f)=abwf,2(x)dx=abwf,3(x)dx.

Stąd i ze wzoru na błąd interpolacji Hermite'a otrzymujemy

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned \lefteqn{ S(f)\,-\,P(f)\;=\;\int_a^b (f-w_{f,3})(x)\,dx } \\ && =\; \int_a^b (x-a)\Big(x-\frac{a+b}2\Big)^2(x-b) f\Big(a,b,\frac{a+b}2,\frac{a+b}2,x\Big)\,dx. \endaligned}

Ponieważ wielomian (xa)(x(a+b)//2)2(xb) jest niedodatni na [a,b], możemy znów zastosować twierdzenie o wartości średniej. Mamy

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned S(f)\,-\,P(f) &= f\Big(a,b,\frac{a+b}2,\frac{a+b}2,c\Big) \\ && \qquad\qquad\qquad \int_a^b (x-a)\Big(x-\frac{a+b}2\Big)^2(x-b)\,dx \\ &= -\frac{f^{(4)}(\xi_2)}{4!}\frac{(b-a)^5}{120}, \endaligned}

co kończy dowód.

Kwadratury złożone

Podobnie jak w przypadku zadania interpolacji chcielibyśmy, aby błąd kwadratur malał do zera, gdy liczba węzłów rośnie do nieskończoności. Można to osiągnąć stosując np. kwadratury złożone. Są to kwadratury, które powstają przez scałkowanie funkcji kawałkami wielomianowej interpolującej f.

Prostym przykładem kwadratury złożonej jest suma Riemanna,

Q¯(f)=i=0n(ti+1ti)f(xi),

gdzie a=t0<t1<<tn+1=b oraz xi[ti,ti+1]. Jeśli średnica podziału, max0in(titi1), maleje do zera to limnQ¯(f)=S(f).

Będziemy rozpatrywać kwadratury złożone postaci

Q¯(f)=abw¯f(x)dx,

gdzie w¯f jest kawałkami wielomianem z Rozdziału Uzupelnic: kawwiel . To znaczy, dla danego n kładziemy ti=a+(ba)i//k, 0ik, a następnie dla każdego i wybieramy dowolne węzły xi,j[ti1,ti], 0jr. Wtedy w¯f jest na każdym przedziale wielomianem interpolacyjnym funkcji f stopnia co najwyżej r opartym na węzłach xi,j. Kwadratura Q¯ korzysta z węzłów o łącznej krotności nk(r+1).

Twierdzenie

Błąd kwadratury złożonej Q¯(f) w klasie FMr([a,b]) jest ograniczony przez

supfFMr([a,b])|S(f)Q¯(f)|(ba)r+2kr+1M(r+1)!C(1n)r+1,

gdzie

C=M(r+1)r+1(ba)r+2(r+1)!.

Dowód\quad Twierdzenie to jest bezpośrednim wnioskiem z Twierdzenia Uzupelnic: twblkw . Mamy bowiem

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned |S(f)-\bar Q(f)| &\le & \sum_{i=1}^k \int_{t_{i-1}}^{t_i} |f(x)-\bar w_f(x)|\,dx \\ &\le & \sum_{i=1}^k \Big(\frac{b-a}{k}\Big)^{r+2} \frac M{(r+1)!} \,=\, \frac{(b-a)^{r+2}}{k^{r+1}}\frac M{(r+1)!}, \endaligned}

co kończy dowód.

W klasie FMr([a,b]), błąd kwadratur złożonych jest rzędu n(r+1), czyli jest taki sam jak błąd interpolacji kawałkami wielomianowej. I tak jak przy interpolacji można pokazać, że błąd każdej innej metody całkowania korzystającej jedynie z wartości funkcji w n punktach nie może w klasie FMr([a,b]) maleć szybciej niż n(r+1), zob. U. Uzupelnic: optzlo . Podane kwadratury złożone mają więc optymalny rząd zbieżności.

Zajmiemy się teraz błędem szczególnych kwadratur złożonych, mianowicie złożonych kwadratur trapezów T¯k i parabol P¯k. Powstają one przez zastosowanie na każdym przedziale [ti1,ti] odpowiednio kwadratur trapezów T i parabol P. Jak łatwo się przekonać,

T¯k(f)=bak(f(a)+f(b)2+j=1k1f(jk)),

oraz

P¯k(f)=ba3k(f(a)+f(b)2+j=1k1f(jk)+2j=1kf(2j12k)).

Twierdzenie

Jeśli fC(2)([a,b]) to

S(f)T¯k(f)=(ba)212k2f(2)(ξ1).

Jeśli fC(4)([a,b]) to

S(f)P¯k(f)=(ba)42280k4f(4)(ξ2).

Dowód

Dla kwadratury trapezów mamy

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned \lefteqn{ S(f)\,-\,\bar T_k(f) \;=\; -\sum_{i=1}^k \frac{(b-a)^3}{12 k^3}f^{(2)}(\alpha_i) } \\ && =\;-\frac{(b-a)^2}{12 k^2}\sum_{i=1}^k \frac{b-a}k f^{(2)}(\alpha_i) \,=\, -\frac{(b-a)^2}{12 k^2} f^{(2)}(\xi_1), \endaligned}

a dla kwadratury parabol podobnie

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned \lefteqn{ S(f)\,-\,\bar P_k(f) \;=\; -\sum_{i=1}^k \frac{(b-a)^5}{2280 k^5}f^{(4)}(\beta_i) } \\ && =\; -\frac{(b-a)^4}{2280 k^4}\sum_{i=1}^k \frac{b-a}k f^{(4)}(\beta_i) \,=\, -\frac{(b-a)^4}{2280 k^4} f^{(4)}(\xi_2). \endaligned}

Kwadratura parabol ma więc optymalny rząd zbieżności nie tylko w klasie FM2([a,b]), ale też w FM3([a,b]).

Przyspieszanie zbieżności kwadratur

W praktyce często stosuje się obliczanie kwadratur poprzez zagęszczanie podziału przedziału [a,b]. Na przykład, dla złożonej kwadratury trapezów zachodzi następujący wygodny wzór rekurencyjny:

T¯2k=12(T¯k(f)+baki=1kf(2i12k)).

Pozwala on obliczyć T¯2k(f) na podstawie T¯k(f) poprzez "doliczenie" wartości funkcji w punktach "gęstszej" siatki. W ten sposób możemy obserwować zachowanie się kolejnych przybliżeń T¯2s(f) (s0) całki S(f). Jest to szczególnie istotne wtedy, gdy nie mamy żadnej informacji a priori o fC([a,b]), a przez to nie potrafimy oszacować liczby n węzłów, dla której osiągniemy pożądaną dokładność, zob. U. Uzupelnic: kwas .

Jeśli funkcja jest więcej niż dwa razy różniczkowalna to użycie złożonych kwadratur trapezów zdaje się tracić sens. Wtedy istnieją przecież kwadratury, których błąd maleje do zera szybciej niż n2. Okazuje się jednak, że kwadratury T¯k mogą być podstawą dla prostej rekurencyjnej konstrukcji innych kwadratur posiadających już optymalną zbieżność. Konstrukcja ta bazuje na następującym ważnym lemacie.

Leonhard Euler
Zobacz biografię
Colin Maclaurin
Zobacz biografię

Lemat Formuła Eulera-Maclaurina

Dla funkcji fC(2m+2)([a,b]), błąd złożonej kwadratury trapezów T¯k wyraża się wzorem

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned S(f)\,-\,\bar T_k(f) &= \sum_{i=1}^{m} c_ih^{2i} \Big(f^{(2i-1)}(b)-f^{(2i-1)}(a)\Big) \\ &&\qquad\qquad\qquad \,+\,c_{m+1}h^{2m+2}(b-a)f^{(2m+2)}(\xi_{m,k}), \endaligned}

gdzie h=(ba)//k, ξm,k[a,b], a ci są pewnymi stałymi liczbowymi. Mamy c1=1//12, c2=1//720 i, ogólnie, ci=Bi//(2i)!, gdzie Bi są tzw. liczbami Bernoulliego.

Dowód tego lematu pominiemy.

Formułę Eulera-Maclaurina można przepisać w postaci

S(f)T¯k(f)=i=1mci(0)(f)k2i+cm+1,k(0)(f)k(2m+2),

gdzie ci(0)(f)=ci(ba)2i(f(2i1)(b)f(2i1)(a)), 1im, oraz cm+1,k(0)(f)=cm+1(ba)2m+2f(2m+2)(ξm+1,k). Zauważmy przy tym, że jeśli fFM2m+1([a,b]) to współczynniki cm+1,k(0)(f) są wspólnie ograniczone przez cm+1(ba)2m+2M.

Definiując teraz kwadraturę

T¯k1(f)=4T¯2k(f)T¯k(f)3,

dla fC(4)([a,b]) mamy

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned S(f)\,-\,\bar T^1_k(f) &= \frac{4\,(S(f)-\bar T_{2k}(f)- (S(f)-\bar T_k(f))}{3} \\ &= \frac 43\left(\frac{c^{(0)}_1(f)}{4k^2}+ \frac{c^{(0)}_{2,2k}(f)}{4^2k^4}\right)\,-\, \frac 13\left(\frac{c^{(0)}_1(f)}{k^2}+ \frac{c^{(0)}_{2,k}(f)}{k^4}\right) \\ &= \frac{c^{(1)}_{2,k}(f)}{k^4}, \endaligned}

gdzie c2,k(1)(f)=(1//12)c2,2k(0)(f)(1//3)c2,k(0)(f) i jest wspólnie ograniczone dla fFM3([a,b]). Kwadratura Tk1 ma więc optymalny w FM3([a,b]) rząd zbieżności k4. Proces ten można kontynuować dalej tworząc kolejne kwadratury o coraz to wyższym rzędzie zbieżności. Dokładniej, połóżmy T¯k0(f)=T¯k(f) oraz, dla s1,

T¯ks(f)=4sT¯2ks1(f)T¯ks1(f)4s1.

Wtedy, dla fFM2m+1([a,b]), rząd zbieżności kwadratury T¯km wynosi k(2m+2). Rzeczywiście, sprawdziliśmy, że jest to prawdą dla m=0,1. Niech m2. Postępując indukcyjnie ze względu na s=1,2,,m mamy

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned \lefteqn{ S(f)\,-\,\bar T^s_k(f) \;=\; \frac{ 4^s(S(f)-\bar T^{s-1}_{2k}(f))- (S(f)-\bar T^{s-1}_k(f)) }{ 4^s\,-\,1 } } \\ &&=\; \left( 4^s\,\left(\sum_{i=s}^{m}c_i^{(s-1)}(f)(2k)^{-2i}+ c_{m+1,2k}^{(s-1)}(f)(2k)^{-(2m+2)}\right)\right. \\ && \left.\quad \,-\,\left( \sum_{i=s}^mc_i^{(s-1)}(f)k^{-2i}+ c_{m+1,k}^{(s-1)}(f)k^{-(2m+2)} \right) \right)\,\frac{1}{4^s\,-\,1}\\ &&=\; \sum_{i=s+1}^m c_i^{(s)}(f)k^{-2i}\,+\, c_{m+1,k}^{(s)}(f)k^{-(2m+2)}, \endaligned}

ponieważ współczynniki przy k2s redukują się. ci(s)(f) są tutaj pewnymi nowymi stałymi, a cm+1,k(s)(f) może być w klasie FM2m+1([a,b]) ograniczona przez stałą niezależną od f. Ostatecznie, dla s=m mamy więc

S(f)T¯km(f)=cm+1,k(m)(f)k(2m+2)

i w klasie FM2m+1([a,b])

|S(f)T¯km(f)|cmk(2m+2)

dla pewnej stałej cm niezależnej od f.

Zauważmy jeszcze, że T¯km wykorzystuje n=k2m+1 wartości f w punktach równoodległych na [a,b] co oznacza, że w terminach n rząd zbieżności wynosi też n(2m+2), a więc jest optymalny w klasie FM2m+1([a,b]).

Kwadratury T¯ks nazywane są kwadraturami Romberga. Dla danej funkcji f, można je łatwo konstruować budując następującą tablicę trójkątną:

T¯10(f)T¯20(f)T¯11(f)T¯40(f)T¯21(f)T¯12(f)T¯80(f)T¯41(f)T¯22(f)T¯13(f)T¯2s0(f)T¯2s11(f)T¯2s22(f)T¯2s33(f)T¯1s(f),

w której pierwsza kolumna jest tworzona indukcyjnie zgodnie ze wzorem (Uzupelnic: indtrap ), a kolejne zgodnie z (Uzupelnic: indRom ).

Biblioteki

W Octave dostępne są jedynie procedury całkujące funkcje skalarne jednej zmiennej na odcinku:

I=abf(x)dx.

Robi to funkcja DQAGP ze znakomitego pakietu QUADPACK. Najlepiej od razu posłużmy się przykładem.

Przykład: Prosta całka funkcji jednej zmiennej

Przypuśćmy, że chcemy obliczyć całkę I=01F(x)dx, gdzie np. F(x)=sin(23x)+(1x2)1/2. W tym celu najpierw implementujemy F w Octave:

function y = F(x)
	y = sin(23*x)+1/sqrt(1-x^2);
endfunction

Aby teraz obliczyć całkę I=01F(x)dx, wystarczy wywołać

I = quad("F", 0, 1);

W rzeczywistości, podobnie jak w przypadku funkcji fsolve, funkcja quad zwraca więcej informacji, można jej także przekazać dodatkowe parametry. I tak, jeśli chcemy ustawić poziom tolerancji błędu obliczenia całki:

Parser nie mógł rozpoznać (błąd składni): {\displaystyle \displaystyle |I - \text{\lstoct{quad(...)}}| \leq \max\{\text{ATOL}, \text{RTOL}\cdot |I|\} }

z wartościami ATOL = 1e-3 i RTOL = 1e-6, to wywołamy funkcję przekazując jej te parametry następująco:

quad("F", 0, 1, [1e-3, 1e-6]);

Musimy jednak pamiętać, by pojęcia tolerancji "błędu" nie traktować zbyt dosłownie: tym, co naprawdę kontroluje quad podczas wyznaczania wartości całki, jest jedynie pewien estymator błędu, dlatego wartość tolerancji należy zawsze wybierać w sposób konserwatywny, czyli z pewnym zapasem bezpieczeństwa, np.

Jeśli chcemy wyznaczyć wartość całki z błędem bezwzględnym na

poziomie 106, ustawimy -- na wszelki wypadek -- ATOL = 1e-7, a nie, prostodusznie, ATOL = 1e-6... Musimy także pamiętać, że choć są bardzo mało prawdopodobne do spotkania w praktyce, to jednak istnieją wyuzdane funkcje, dla których estymator błędu może dać całkowicie fałszywe wartości,

przez co i obliczona całka może być obarczona dowolnie wielkim błędem.

Dodajmy, że quad doskonale radzi sobie także z funkcjami z osobliwościami (o ile tylko ją o nich uprzedzimy). Przykładowo, scałkujmy funkcję ze złośliwą nieciągłością w zerze:

Parser nie mógł rozpoznać (nieznana funkcja „\begincases”): {\displaystyle \displaystyle f(x) = \begincases \frac{1}{x}, \qquad x\neq 0,\\ 10^6, \qquad x=0. \endcases }

Oczywiście, 11f(x)dx=0, tymczasem definiując

function y = osobliwa(x)
if (x != 0.0)
	y = 1/x;
else
	y = 1e6;
endif
endfunction

quad("osobliwa", -1, 1)

daje w rezultacie

ABNORMAL RETURN FROM DQAGP ans = -81.098

-- błędny wynik i (na szczęście!) także komunikat o jakichś problemach procedury całkującej. Jeśli jednak wspomożemy quad informacją o tym, że w x=0 czai się osobliwość, wszystko przebiegnie już gładko:

quad("osobliwa", -1, 1, [1e-8 1e-8], 0) ans = 0

(1e-8 jest żądaną tolerancją błędu, równą wartości domyślnej).

QUADPACK

Właściwie jedynym klasycznym pakietem, jaki mamy do dyspozycji jest ponaddwudziestoletni QUADPACK . Jest to zestaw kilkunastu procedur fortranowskich, służących obliczaniu typowych całek jednowymiarowych, w tym kilka ogólnego stosowania:

Typ całki Procedura QUADPACKa
abf(x) DQNG, DQAG, DQAGS, DQAGP
f(x) DQAGI
abf(x)cos(ωx) DQAWO
abf(x)xc DQAWC

oraz spora liczba podstawowych kwadratur, na których oparto te ogólne. Nazwy procedur rozszyfrowuje się podobnie jak nazwy procedur LAPACKa, zatem

  • przedrostek D w nazwie każdej procedury wymienionej w tabeli (np. DQAGI) oznacza, że będzie działać na liczbach typu double (całkując funkcję f zwracającą wartości tego samego typu). Gdybyśmy chcieli użyć pojedynczej precyzji, użylibyśmy nazwy procedury bez przedrostka.
  • Kolejna litera, Q, oczywiście oznacza kwadraturę (Quadrature).
  • Trzecia litera --- A lub N oznacza, odpowiednio, kwadraturę adaptacyjną lub nieadaptacyjną. Jak wiadomo, w praktyce lepiej sprawdzają się kwadratury adaptacyjne, potrafiące w jakiejś mierze dostosować się do przebiegu funkcji podcałkowej. Kwadratury nieadaptacyjne nie mają tej własności, natomiast są tańsze, warto więc je stosować w szczególnych przypadkach, gdy wiemy a priori, że adaptacja niewiele pomoże: np. do wolno zmiennych funkcji.
  • Pozostałe litery precyzują typ liczonej całki i zakres ingerencji użytkownika; G --- "zwykła" całka, bez wagi, W --- całka z wagą, O --- oscylacyjną, C --- wartość główna całki (tzw. całka Cauchy'ego), I --- przedział nieskończony, S --- możliwe osobliwości, P --- użytkownik poda listę punktów, gdzie są osobliwości.

GSL

Biblioteka GSL reimplementuje podstawowe procedury QUADPACKa w języku C, zob. {GSL-reference}, gdzie zostały one bardzo przystępnie i szczegółowo opisane. Procedury GSL mają nazwy analogiczne, jak procedury QUADPACKa, ale z przedrostkiem gsl_integration, jak w poniższym przykładzie, gdzie wywołamy odpowiednik procedury DQAG: funkcję gsl_integration_qag.

#include <stdio.h>
#include <math.h>
#include <gsl/gsl_integration.h>

double F(double X, void * param) /* wrapper dla funkcji sin(x)/x */
{
	return(sin(X)/X);
}

int main(void)
{
	gsl_function f; /* argument z funkcją podcałkową */

	double A,ABSERR,B, EPSABS,EPSREL,RESULT;
	int IER,NEVAL;

	gsl_integration_workspace *workspace;

	int KEY, LIMIT; 

	/* przygotowujemy argument z funkcją podcałkową */
	f.function = &F;
	
	A = 0.0E0; B = 10*M_PI; /* przedział całkowania */
	EPSABS = 0.0E0; EPSREL = 1.0E-3; /* tolerancja błędu */

	/* parametry specyficzne dla QAG */
	KEY = 1; /* tzn. użyj minimalnej liczby punktów kwadratury bazowej */
	LIMIT = 100; /* maksymalny podział przedziału całkowania */
	workspace  = gsl_integration_workspace_alloc(LIMIT);
	
	/* całkujemy: QAG! */

	IER = gsl_integration_qag(&f, A, B, EPSABS, EPSREL, 
					LIMIT, KEY, workspace, &RESULT, &ABSERR);

	if (IER != 0)
		fprintf(stderr,"GSL_QAG: Kłopoty z całkowaniem\n");
	fprintf(stderr,"Całka: %g Est. błąd: %g IER: %d\n", RESULT, ABSERR,  IER);

	gsl_integration_workspace_free(workspace);
	
	return(0);
}

W powyższym przykładzie specjalnie pozostawiliśmy oznaczenia wykorzystywane w poprzednim programie. Jak widać, funkcje całkujące GSL mają bardzo podobną składnię do odpowiadających im funkcji QUADPACKa.

Miłym rozszerzeniem funkcjonalności jest możliwość przekazywania parametrów do wnętrza funkcji podcałkowej.

Różniczkowanie

<<< Powrót do strony głównej przedmiotu Metody numeryczne

Z zadaniem numerycznego różniczkowania zadanej funkcji spotykamy się często w numeryce. Rzeczywiście, jeśli przypomnimy sobie metodę siecznych, to była to po prostu metoda Newtona, w której pochodną przybliżono pewnym ilorazem różnicowym:

xk+1=xkf(xk)gk,

gdzie

gk=f(xk)f(xk1)xkxk1f(xk).

Zauważmy, że nie jest to jedyny możliwy wzór na przybliżoną metodę Newtona, równie dobrze(? --- to się dopiero okaże!) moglibyśmy wziąć

gk=f(xk+h)f(xk)h
dla dostatecznie małego h. 

Podobne formuły są także konieczne do konstrukcji metod numerycznego rozwiązywania równań różniczkowych, gdzie w naturalny sposób pojawia się konieczność operowania pochodną nieznanej funkcji.

Metody różnicowe

Rozważmy najprostszy sposób aproksymacji pochodnej f(x), oparty na różnicy dzielonej w przód, gdyż ze wzoru Taylora

f(x+h)=f(x)+f(x)h+O(h2),

pomijając człony rzędu h2, dostajemy przybliżenie

f(x)f(x+h)f(x)h,

a dokładniej,

f(x)=f(x+h)f(x)h+O(h).

Podobną dokładność aproksymacji dostaniemy, biorąc różnicę dzieloną w tył,

f(x)=f(x)f(xh)h+O(h).

Nietrudno przekonać się, że wzięcie średniej arytmetycznej tych dwóch aproksymacji daje tzw. różnicę centralną, która ma wyższy rząd aproksymacji, gdyż

f(x)=f(x+h)f(xh)2h+O(h2),

co znaczy, że dwukrotnie zmniejszając h, powinniśmy się spodziewać czterokrotnego zmniejszenia błędu aproksymacji pochodnej!

Metody interpolacyjne

Jeśli chcemy uzyskać jeszcze wyższy rząd aproksymacji pochodnej, często jako wyrażenie aproksymujące przyjmuje się pochodną wielomianu interpolacyjnego.

Rzeczywiście, niech wn będzie wielomianem interpolującym funkcję f w parami różnych węzłach x0<<xn, tzn.

wn(x)=i=0nf(xi)li(x),

gdzie li(x) są \link{sec:interpol}{wielomianami bazowymi Lagrange'a}. Wtedy

f(x)wn(x)=i=0nf(xi)li(x),

przy czym można wykazać, że

Twierdzenie O błędzie aproksymacji pochodnej za pomocą pochodnej wielomianu interpolacyjnego

Niech wn będzie wielomianem interpolującym funkcję fCn+2[a,b] w równoodległych węzłach a,a+h,a+2h,,b, gdzie h=(ba)/n. Wtedy zachodzi

f(x)wn(x)=O(hn)x[a,b]

Wszystkie wprowadzone powyżej metody interpolacji oparte na wielomianie Taylora w rzeczywistości dadzą się sprowadzić do pochodnej wielomianu interpolacyjnego. Rzeczywiście,

  • różnica w przód to aproksymacja f(x) pochodną wielomianu opartego na węzłach x i x+h,
  • różnica w tył to aproksymacja f(x) pochodną wielomianu opartego na węzłach x i xh,
  • różnica centralna to aproksymacja f(x) pochodną wielomianu opartego na węzłach xh i x+h; w tym ostatnim przypadku widzimy także, że powyższe twierdzenie nie zawsze jest ostre, bo dla różnicy centralnej byliśmy w stanie uzyskać wyższy niż minimalny gwarantowany przez twierdzenie rząd aproksymacji.

Łatwo także --- korzystając z powyższego --- wyprowadzić nowe wzory na aproksymację, przykładowo,

f(x)=12h(3f(x)4f(xh)+f(x2h))+O(h2)

korzysta tylko z wartości f na lewo od x (jest to więc różniczkowanie wstecz) i też daje kwadratową aproksymację.

Analogicznie możemy aproksymować pochodne wyższych rzędów, np.

f(x)=f(xh)2f(x)+f(x+h)h2+O(h2).

Tę formułę możemy znów uzyskać na wiele sposobów:

  • wprost ze wzoru Taylora, raz dla f(x+h), a raz dla f(xh),
  • jako drugą pochodną wielomianu interpolacyjnego,
  • jako złożenie różnicy dzielonej w przód z różnicą dzieloną w tył (co ma naśladować matematyczną zależność, że f(x)=(f(x)).

Namawiamy czytelnika do sprawdzenia, że faktycznie powyższy wzór można tak wyprowadzić.


Uwarunkowanie

Kłopoty numeryczne

Rozważmy przykładowo różnicę w przód dla h>0. Gdyby arytmetyka której używamy miała nieskończoną precyzję, to oczywiście zachodzi

f(x+h)f(x)hf(x)=O(h),

i przybliżenie byłoby tym lepsze, im mniejsze byłoby h. Jednak w praktyce tak nie będzie, ze względu na fakt, że działamy w arytmetyce skończonej precyzji:

  • dla małych h, mamy f(x+h)f(x)0, a więc zachodzi duże ryzyko utraty cyfr przy odejmowaniu
  • dla małych h, może zdarzyć się, że numerycznie flν(x+h)=flν(x) i w konsekwencji flν(f(x+h)f(x)h)=0.

Można więc postawić sobie pytanie, jak dobrać h na tyle małe, by mieć możliwie dobrą aproksymację f(x), a jeszcze nie odczuć zgubnych skutków wpływu arytmetyki zmiennoprzecinkowej. Formalnie, możemy pytanie postawić w sposób następujący:

Przypuśćmy, że zamiast

f(x)

wyznaczane jest

f~(x)=f(x)+ϵx

, przy czym

|ϵx|ϵ

. Jak dobrać do

ϵ

parametr

h

w taki sposób, by aproksymacja

f~(x+h)f~(x)hf(x)
była jak najlepsza?

Mamy:

Parser nie mógł rozpoznać (nieznana funkcja „\aligned”): {\displaystyle \displaystyle \aligned \left| \frac{\tilde{f}(x+h)-\tilde{f}(x)}{h} - f'(x) \right| &= \left| \frac{1}{h}( (f(x+h)+\epsilon_{x+h}) - (f(x) + \epsilon_x)) - f'(x) \right| \\ &\leq \left| \frac{ f(x+h) - f(x)}{h} - f'(x)\right| + \frac{2\epsilon}{h} \endaligned}

Ponieważ pierwszy człon wyrażenia daje się oszacować (dla dostatecznie regularnej funkcji f) przez Ch, to ostatecznie dostajemy

|f~(x+h)f~(x)hf(x)|C1(h+1h).

Wyrażenie po prawej stronie jest minimalizowane dla h=ϵ i stąd inżynierska reguła:

Jeśli chcesz używać różnicy w przód, powinieneś wziąć h równe co najmniej ϵmach.