Całkowanie numeryczne metodą Simpsona

superdurszlak

Wstęp

Metoda Simpsona jest bardziej zaawansowaną metodą obliczania całki przez przybliżenie pola pod wykresem, która od metody trapezów różni się stopniem wielomianu, którym przybliżana jest funkcja w poszczególnych przedziałach - o ile w metodzie trapezów wielomian był pierwszego stopnia (f. liniowa) przechodzący przez 2 punkty, to w metodzie Simpsona stosujemy wielomian interpolacyjny drugiego stopnia (parabola) przechodzący przez 3 punkty.

Przybliżenie funkcji wielomianem interpolacyjnym w oparciu o 3 punkty

Z tego względu dla 2N + 1 punktów (czyli 2N przedziałów) funkcja będzie przybliżana przez N wielomianów:

Metoda Simpsona - wykorzystanie dodatkowych punktów pośrodku poszczególnych przedziałów

Całkę przybliżamy stosując następujący wzór:

\int_{a}^{b}f(x)dx\approx \sum_{i=0}^{N-1}\frac{h \cdot{}(f(x_{2i}) + 4f(x_{2i+1})+ f(x_{2i+2}))}{3}

Gdzie:

h = \frac{b-a}{N}\hspace{40mm}x_{i} = a + hi \hspace{40mm}b > a

Ponieważ obliczenie całki wprost z tego wzoru wymagałoby (pomijając obliczanie xi) 3N - 1 dodawań, 2N mnożeń oraz N dzieleń, możemy dokonać przekształcenia, pozwalającego zredukować liczbę operacji arytmetycznych do 2N dodawań, 3 mnożeń i 1 dzielenia:

\int_{a}^{b}f(x)dx\approx h \cdot{} (\frac{f(x_{0})+f(x_{2N}) + 4\cdot\sum_{i=0}^{N-1}f(x_{2i+1}) + 2\cdot\sum_{i=0}^{N-2}f(x_{2i+2})}{3} )

Implementacja w Pythonie

Dla przejrzystości pominiemy walidację argumentów i obsługę błędów.

Postać oryginalna

def simpson_integration_simple(my_func, a, b, n):
  # Szerokość pojedynczego przedziału
  delta_x = (b-a)/n
  # x_i liczymy każdorazowo od nowa by uniknąć kumulowania 
  # się błędów numerycznych - kosztem dużej ilości mnożeń
  total = 0  
  # pamiętamy że n = 2N
  for i in range(0, n, 2):
    x = a + delta_x * 2 * i
    total += delta_x * (my_func(x) + 4 * my_func(x + delta_x) + my_func(x + 2 * delta_x) / 3
  return total

# Wywołujemy naszą funkcję całkującą, przekazując wzór całkowanej funkcji jako lambdę
integral = simpson_integration_simple(lambda x: x**2, 0.0, 1.0, 100)

Postać przekształcona

def simpson_integration_modified(my_func, a, b, n):
  # Szerokość pojedynczego przedziału
  delta_x = (b-a)/n
  total = my_func(a) + my_func(b)
  subtotal_sum_1 = 0
  subtotal_sum_2 = 0
  # pierwsza suma, pamiętamy że n = 2N
  for i in range(0, n, 2):
    x = a + i * delta_x
    subtotal_sum_1 += my_func(x)
  # druga suma, pamiętamy że n = 2N
  for i in range(1, n-1, 2):
    x = a + i * delta_x
    subtotal_sum_2 += my_func(x)
  return delta_x * (total + 4 * subtotal_sum_1 + 2 * subtotal_sum_2) / 3

# Wywołujemy naszą funkcję całkującą, przekazując wzór całkowanej funkcji jako lambdę
integral = simpson_integration_modified(lambda x: x**2, 0.0, 1.0, 100)

Przykłady

Przykład 1: funkcja kwadratowa

TODO: przedstawić przykład krok po kroku z wynikami

Przykład 2: funkcja cosinus

TODO: przedstawić przykład krok po kroku z wynikami

0 komentarzy