Wyobraźmy sobie, że stajemy przed zadaniem obliczenia pola powierzchni pod wykresem pewnej funkcji, na zadanym przedziale [t1,t2]. Komputery, z racji swojej oszałamiającej wręcz (w porównaniu z mózgiem człowieka) zdolności do szybkiego wykonywania obliczeń, nadają się do tego zadania idealnie. Jako że dana funkcja może być niezwykle skomplikowana, musimy się często jednak zadowolić rozwiązaniami przybliżonymi, o dokładności zależnej od tego, jak wiele czasu możemy poświęcić na oczekiwanie na wynik.
Wydawać by się mogło, że problem obliczania pola powierzchni pod wykresem jest bardzo abstrakcyjny. W praktyce jednak spotyka się go dość często. Przykładowo, jeśli wiemy, jak zmieniała się prędkość obiektu poruszającego się po prostej w czasie (patrz rysunek 1), możemy wyznaczyć drogę, jaką pokonał on w danym przedziale czasu, obliczając wartość pola powierzchni pod odpowiednim fragmentem wykresu.
Rysunek 1. Fragment wykresu funkcji v(t)
Jeśli prędkość v jest stała w czasie (a więc gdy mamy do czynienia z~ruchem jednostajnym prostoliniowym), to pole powierzchni pod wykresem na przedziale [t1,t2] jest równe v⋅(t2−t1), skąd — jeśli t1=0 — otrzymujemy znany nam wszystkim z lekcji fizyki wzór na drogę: s=vt.
Do przybliżania pola powierzchni pod wykresem* w przedziale [a,b] wykorzystuje się procedury numeryczne. Ich idea jest dość intuicyjna: dzielimy zadany przedział na n równych podprzedziałów (oznaczanych [x0,x1],[x1,x2], …,[xn−1,xn], takich że x0:=a i xn:=b), następnie przybliżamy (w pewien sposób) pole powierzchni pod wykresem w każdym z tych podprzedziałów, by na końcu zsumować otrzymane wyniki.** Dlaczego dzielimy przedział na podprzedziały? Jest to naturalna konsekwencja niemego założenia, że na odpowiednio małym przedziale wykres badanej funkcji da się przybliżyć przy użyciu obiektów, których własności znamy — choćby prostych (wykresów funkcji liniowych) lub parabol (wykresów funkcji kwadratowych).
Metody przybliżania
Pole powierzchni pod wykresem funkcji f na podprzedziale [xi,xi+1], gdzie i∈{0,1,…,n−1}, możemy przybliżyć na niezliczoną liczbę sposobów, spośród których trzy najpopularniejsze to przybliżanie:
- polem prostokąta o szerokości równej xi+1−xi=b−an i wysokości równej wartości funkcji f w środku przedziału (patrz rysunek 2a)
- polem trapezu o długości podstawy równej xi+1−xi=b−an oraz długości lewego boku równej wartości funkcji f w punkcie xi i długości prawego boku równej wartości funkcji f w punkcie xi+1 (patrz rysunek 2b),
- polem powierzchni pod wykresem funkcji kwadratowej, której wykres przechodzi przez punkty (xi,f(xi)), (xi+xi+12,f(xi+xi+12)) oraz (xi+1,f(xi+1)), na przedziale [xi,xi+1] (patrz rysunek 2c).
![]() Rysunek 2a. Metoda prostokątów |
![]() Rysunek 2b. Metoda trapezów |
![]() Rysunek 2c. Metoda Simpsona |
O ile dwie pierwsze metody są raczej dość intuicyjne, o tyle ostatnia (zwana \emph{metodą Simpsona}) wymaga pewnego dodatkowego komentarza.
Skąd wiadomo, jak wygląda wykres funkcji kwadratowej, który przechodzi przez wskazane punkty? Okazuje się, że istnieje co najwyżej jeden wielomian stopnia k przechodzący przez k+1 różnych (względem pierwszej współrzędnej) punktów. Jeśli więc wartości xi oraz xi+1 są różne (dlaczego to wystarczy?), to istnieje \emph{co najwyżej jedna} funkcja kwadratowa, której wykres przechodzi przez punkty (xi,f(xi)), (xi+xi+12,f(xi+xi+12)) oraz (xi+1,f(xi+1)). Taka funkcja nie istnieje jednak, jeśli trzy badane punkty leżą na jednej prostej.
Pewne matematyczne przekształcenia wskazują, że pole powierzchni pod parabolą przechodzącą przez określone wyżej punkty, na przedziale [xi,xi+1], wyraża się wzorem xi+1−xi6(f(xi)+f(xi+1)+4f(xi+xi+12)). Gdy przyjrzymy się temu wzorowi, okaże się, że jeśli punkty (xi,f(xi)), (xi+xi+12,f(xi+xi+12)) oraz (xi+1,f(xi+1)) leżą na jednej prostej, to obliczone pole jest równoważne polu obliczonemu metodą trapezów. Nie musimy się więc przejmować tym przypadkiem.
Optymalizacja
Celem tego artykułu jest implementacja kilku funkcji w języku C. Zastosowanie powyższych rozważań wprost spowodowałoby, że wartość funkcji f byłaby obliczana wielokrotnie w tych samych punktach, co wymagałoby więcej mocy obliczeniowej niż to konieczne. Spróbujmy więc zoptymalizować obliczenia na poziomie sumowania pól powierzchni. Jeśli przez P(a,b) oznaczymy właściwe pole powierzchni pod wykresem funkcji f na przedziale [a,b], to w przypadku metody prostokątów otrzymujemy \begin{array}{rcl} P(a, b) & \approx & \sum_{i=0}^{n-1} (x_{i+1} – x_i)\cdot f\Bigl(\frac{x_{i+1}+x_i}{2}\Bigr)\\ & = & \sum_{i=0}^{n-1} \frac{b – a}{n}\cdot f\Bigl(\frac{x_{i+1}+x_i}{2}\Bigr)\\ & = & \frac{b – a}{n}\cdot\sum_{i=0}^{n-1} f\Bigl(\frac{x_{i+1}+x_i}{2}\Bigr), \end{array} w przypadku metody trapezów otrzymujemy \begin{array}{rcl} P(a, b) & \approx & \sum_{i=0}^{n-1} (x_{i+1} – x_i)\cdot \frac{f(x_i) + f(x_{i+1})}{2}\\ & = & \sum_{i=0}^{n-1} \frac{b – a}{n}\cdot \frac{f(x_i) + f(x_{i+1})}{2}\\ & = & \frac{b – a}{2n}\cdot\sum_{i=0}^{n-1} \bigl(f(x_i) + f(x_{i+1})\bigr)\\ & = & \frac{b – a}{2n}\cdot\bigl( f(x_0) + f(x_n) + 2\cdot\sum_{i=1}^{n-1} f(x_i) \bigr), \end{array} a w przypadku metody Simpsona \begin{array}{rcl} P(a, b) & \approx & \sum_{i=0}^{n-1} \frac{x_{i+1}-x_i}{6}\Bigl(f(x_i)+f(x_{i+1}) + 4f\Bigl(\frac{x_{i}+x_{i+1}}{2}\Bigr)\Bigr)\\ & = & \sum_{i=0}^{n-1} \frac{b-a}{6n}\Bigl(f(x_i)+f(x_{i+1}) + 4f\Bigl(\frac{x_{i}+x_{i+1}}{2}\Bigr)\Bigr)\\ & = & \frac{b – a}{6n}\cdot\sum_{i=0}^{n-1} \Bigl(f(x_i)+f(x_{i+1}) + 4f\Bigl(\frac{x_{i}+x_{i+1}}{2}\Bigr)\Bigr)\\ & = & \frac{b – a}{6n}\cdot\Bigl(f(x_0) + f(x_n) + 2\cdot\sum_{i=1}^{n-1}f(x_i)+ 4\cdot\sum_{i=0}^{n-1}f\Bigl(\frac{x_{i}+x_{i+1}}{2}\Bigr)\Bigr).\\ \end{array}
Przykład Niech dana będzie funkcja f(x) = 1+0.1\cdot\sin{(5x)}\cdot\cos{(3x)}. Spróbujmy obliczyć pole pod jej wykresem na przedziale [0, 10], wykorzystując każdą z poznanych metod oraz dzieląc przedział [0, 10] na 5, 10, 15, \dots, 95 oraz 100 części. Otrzymane wyniki są następujące:
n | Metoda przybliżania | ||
---|---|---|---|
prostokątów | trapezów | Simpsona | |
5 | 10.08866501 | 9.97829056 | 10.05187321 |
10 | 9.98090553 | 10.03347683 | 9.99843025 |
15 | 10.05642509 | 9.97654533 | 10.02979946 |
20 | 10.03069878 | 10.00719261 | 10.02286148 |
25 | 10.02630901 | 10.01367569 | 10.02209663 |
30 | 10.02459717 | 10.01648712 | 10.02189255 |
35 | 10.02371883 | 10.01801109 | 10.02181721 |
40 | 10.02320099 | 10.01894379 | 10.02178288 |
45 | 10.02286720 | 10.01956081 | 10.02176476 |
50 | 10.02263641 | 10.01999187 | 10.02175617 |
55 | 10.02247334 | 10.02030563 | 10.02175045 |
60 | 10.02234840 | 10.02053833 | 10.02174568 |
65 | 10.02225494 | 10.02072144 | 10.02174473 |
70 | 10.02218056 | 10.02086449 | 10.02174473 |
75 | 10.02212429 | 10.02097797 | 10.02174282 |
80 | 10.02207565 | 10.02107430 | 10.02173901 |
85 | 10.02203560 | 10.02114868 | 10.02173996 |
90 | 10.02200031 | 10.02121544 | 10.02173901 |
95 | 10.02197742 | 10.02126789 | 10.02173805 |
100 | 10.02195358 | 10.02131653 | 10.02173901 |
Kod źródłowy programu wykonującego obliczenia
#include <stdio.h> #include <math.h> float f(float x){ return 1 + 0.1*sin(5*x)*cos(3*x); } float approxRect(float a, float b, int n, float (*f)(float)){ int i; float range = (b-a)/n; float res = 0; float x; for(i=0; i<n; i++){ x = a + range*i + range/2; res = res + (*f)(x); } return res * range; } float approxTrap(float a, float b, int n, float (*f)(float)){ int i; float range = (b-a)/n; float res = 0; float x; res = res + (*f)(a) + (*f)(b); for(i=1; i<n; i++){ x = a + range*i; res = res + 2 * (*f)(x); } return (res * range)/2; } float approxSimpson(float a, float b, int n, float (*f)(float)){ int i; float range = (b-a)/n; float res = 0; float xi, xii; res = res + (*f)(a) + (*f)(b); for(i=0; i<n; i++){ xi = a + range*i; xii = xi + range; if(i>0) res = res + 2*(*f)(xi); res = res + 4*(*f)((xi+xii)/2); } return (res * range)/6; } int main(){ int n; for(n=5; n<=100; n+=5){ printf("%3d %12.8f %12.8f %12.8f\n", n, approxRect(0, 10, n, &f), approxTrap(0, 10, n, &f), approxSimpson(0, 10, n, &f)); } return 0; }
* Wartość pola powierzchni pod wykresem funkcji f na zadanym przedziale [a, b] to nic innego jak całka oznaczona z funkcji f na tym przedziale.
** Bardziej wnikliwi obserwatorzy zadadzą z pewnością pytanie, dlaczego możemy umieścić punkty graniczne w dwóch sąsiadujących przedziałach jednocześnie. Jest tak dlatego, że pole powierzchni pod wykresem na przedziale o długości 0 jest równe 0.