|
Serwis Edukacyjny w I-LO w Tarnowie
Materiały dla uczniów liceum |
Wyjście Spis treści Wstecz Dalej
Autor artykułu: mgr Jerzy Wałaszek |
©2026 mgr Jerzy Wałaszek
|
| SPIS TREŚCI REMANENT |
|
| Podrozdziały |
W interpolacji wielomianowej przybliżamy funkcję f(x) wielomianem WNN-1(x), gdzie NN - 1 to stopień wielomianu równy liczbie węzłów interpolacji NN pomniejszonej o 1. Aby zrozumieć, jak to działa, przeanalizujmy kilka przykładów.
Mamy pewną funkcję y = f(x), w której są wyznaczone dwa węzły - (x0,y0) i (x1,y1): y0 = f(x0); y1 = f(x1).

Ponieważ NN = 2 (liczba węzłów), to funkcję f(x) będziemy interpolować wielomianem pierwszego stopnia, czyli dwumianem liniowym:

Mamy przepis dwumianu W1(x), musimy znaleźć wartości współczynników a1 i a0.
Wykorzystamy fakt, iż w węzłach funkcja f(x) oraz dwumian W1(x) przyjmują tę samą wartość. Otrzymujemy układ dwóch równań, gdzie niewiadomymi są wartości współczynników dwumianu:

Wykorzystamy wzory wyprowadzone w rozdziale o układzie 2 równań liniowych:

Gdy mamy wyliczone współczynniki, możemy napisać wzór na wielomian interpolujący:

Otrzymaliśmy wzór równania prostej przechodzącej przez oba węzły (x0,y0) i (x1,y1):

Teraz wartości funkcji f(x) przybliżamy wartościami wielomianu. W tej postaci jest to dokładny odpowiednik interpolacji liniowej.
Jeśli mamy trzy węzły interpolacyjne, to postępujemy w sposób identyczny:

Dla trzech węzłów (x0,y0), (x1,y1), (x2,y2), NN = 3:

W trójmianie kwadratowym mamy trzy współczynniki: a0, a1 i a2. Aby je wyznaczyć, tworzymy układ trzech równań, gdzie niewiadomymi są wartości tych współczynników:

Układ rozwiązujemy za pomocą jednej z metod rozwiązywania układów równań liniowych, np. Gausa-Crouta i otrzymujemy wartości współczynników trójmianu. Wartości funkcji interpolujemy wartościami trójmianu.

Przy większej liczbie węzłów zasada jest wciąż identyczna. Wielomian interpolacyjny ma postać:

Jeśli mamy NN węzłów interpolacyjnych, tworzymy układ NN równań liniowych, gdzie niewiadomymi są współczynniki wielomianu interpolacyjnego, a współczynnikami to potęgi współrzędnej xi węzła oraz współrzędnej yi jako wyraz wolny:

Układ równań rozwiązujemy i otrzymujemy współczynniki ai wielomianu. Wielomian używamy do obliczania przybliżonej wartości funkcji.
Im więcej węzłów, tym dokładniej można wyliczać wartość funkcji. Na pierwszy rzut oka wszystko wygląda wspaniale. Układy równań liniowych możemy efektywnie obliczać. Tu nie ma problemów. Czyli wielomian interpolacyjny dostaniemy dosyć łatwo. Jednakże przy dużej liczbie węzłów otrzymujemy wielomian o wysokim stopniu, który zawiera wysokie potęgi x. Takie potęgi są niestabilne numerycznie - nawet drobna zmiana x, może dawać dużą zmianę wartości potęgi, np. załóżmy, że mamy we wzorze x20:

Zauważ, iż drobna zmiana wartości x o 0,001, daje zmianę o ponad 382 miliardy. W efekcie wartość wielomianu interpolacyjnego może daleko odbiegać od wartości funkcji pomiędzy węzłami. Nosi to nazwę efektu Rungego.

Z tego powodu matematycy szukali innych rozwiązań problemu interpolacji. Zwróć uwagę, iż przy wyprowadzaniu wielomianu interpolującego nie zakładaliśmy nic na temat rozkładu węzłów. Mogą one być podane w dowolnej kolejności i nie muszą być rozłożone równomiernie w przedziale interpolacji (muszą jedynie być różne). W rzeczywistości rozkład równoodległy węzłów jest nawet niekorzystny z uwagi na efekt Rungego. Przy stałej odległości między węzłami i wysokim stopniu wielomianu, na krańcach przedziału pojawiają się gwałtowne oscylacje. Aby temu zapobiec, stosuje się zagęszczanie węzłów blisko krańców przedziału


Przedział <-π/2;π/2>. W przedziale program generuje 6 pseudolosowych współrzędnych x bez powtórzeń, wylicza dla nich współrzędną y wg przepisu funkcji i dostaje współrzędne 6 węzłów interpolacyjnych. Tworzy układ 6 równań liniowych z wartościami współrzędnych węzłów i wylicza wartości współczynników wielomianu interpolującego:

W programie powstaje układ 6 równań, w których niewiadomymi są współczynniki wielomianu interpolującego:

Macierz rozszerzona układu jest następująca:

C++// Interpolacja wielomianowa
// (C)2026 mgr Jerzy Wałaszek
// Metody numeryczne 0074
//---------------------------
#include <iostream>
#include <windows.h>
#include <iomanip>
#define _USE_MATH_DEFINES
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
// STAŁE
//------
// Przedział interpolacji
// od XS do XE
const double XS = -M_PI / 2;
const double XE = M_PI / 2;
// liczba węzłów
const int NN = 6;
// Liczba interpolowanych
// punktów
const int N = 10;
// Dokładność przyrównania do 0
const double EPS = 0.00001;
// Tablice
//--------
// Współrzędne x węzłów
double nx[NN];
// Współrzędne y węzłów
double ny[NN];
// Współczynniki wielomianu
double a[NN];
// Funkcje
//--------
// Funkcja interpolowana
//----------------------
double f(double x)
{
return sin(x);
}
// Funkcja zwraca wartość
// pseudolosową w przedziale
// <0,1)
//--------------------------
double random()
{
return rand() /
((double)RAND_MAX + 1);
}
// Funkcja wyznacza węzły
// dla wielomianu
//-----------------------
void set_nodes()
{
// Dwa pierwsze węzły
// definiują przedział
// interpolacji
nx[0] = XS;
nx[1] = XE;
// Pozostałe punkty są
// rozsiane po przedziale
int i = 2,j;
double xx,dx;
// minimalna odległość w osi OX
// pomiędzy węzłami
dx = (XE - XS) / 2 / NN;
while(i < NN)
{
xx = XS + random() * (XE - XS);
bool t = false;
for(j = 0; j < i; j++)
// Sprawdzamy odległość
// węzłów w osi OX
if(fabs(xx - nx[j]) < dx)
{
t = true;
break;
}
// Węzeł za blisko innego,
// losujemy go ponownie
if(t) continue;
nx[i++] = xx;
}
// Dla współrzędnych x
// liczymy współrzędne y
for(i = 0; i < NN; i++)
ny[i] = f(nx[i]);
}
// Oblicza wartość wielomianu
//---------------------------
double f_i(double x)
{
// Współczynnik przy x^(NN-1)
double w = a[NN - 1];
int i;
for(i = NN-1; i > 0; i--)
{
w *= x;
w += a[i-1];
}
return w;
}
// Funkcja rozwiązuje układ równań
// metodą eliminacji Gaussa
// NN - stopień macierzy
// AB - macierz rozszerzona NN x (NN + 1)
// X - macierz rozwiązań NN x 1
// Jeśli układ został rozwiązany,
// to wynikiem jest true.
// Inaczej wynikiem jest false.
//--------------------------------
bool GaussCrout(double AB[][NN+1],
double X[NN])
{
int i,j,k;
double m,s;
int WK[NN + 1];
// Przygotowujemy wektor
// kolumnowy
for(i = 0; i <= NN; i++)
WK[i] = i;
// Eliminacja
for(i = 0; i < NN - 1; i++)
{
for(k = i, j = i + 1; j < NN; j++)
if(fabs(AB[i][WK[k]]) <
fabs(AB[i][WK[j]]))
k = j;
if(k != i)
swap(WK[k],WK[i]);
if(fabs(AB[i][WK[i]]) < EPS)
{
return false;
}
for(j = i + 1; j < NN; j++)
{
m = -AB[j][WK[i]] / AB[i][WK[i]];
for(k = i + 1; k <= NN; k++)
AB[j][WK[k]] += m * AB[i][WK[k]];
}
}
// Obliczanie wartości niewiadomych
for(i = NN - 1; i >= 0; i--)
{
if(fabs(AB[i][WK[i]]) < EPS)
{
return false;
}
s = AB[i][NN];
for(j = NN - 1; j > i; j--)
s -= AB[i][WK[j]] * X[WK[j]];
X[WK[i]] = s / AB[i][WK[i]];
}
return true;
}
// Program główny
//---------------
int main()
{
int i,j;
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
cout << setprecision(4)
<< fixed;
// Inicjujemy generator
// pseudolosowy
srand(time(nullptr));
// Generujemy węzły
set_nodes();
// Tworzymy macierz
// układu równań
double ab[NN][NN+1];
for(i = 0; i < NN; i++)
{
// W ostatniej kolumnie
// są współrzędne y
ab[i][NN] = ny[i];
// W pierwszej są 1
ab[i][0] = 1;
// Pozostałe są potęgami
for(j = 1; j < NN; j++)
ab[i][j] = nx[i] * ab[i][j-1];
}
// Wyznaczamy współczynniki
// wielomianu
if(GaussCrout(ab,a))
{
cout <<
"Interpolacja wielomianowa\n"
"-------------------------\n\n";
// Generujemy N punktów x
// i liczymy dla nich y
// przy pomocy wielomianu
// i wyświetlamy wynik
double x,y;
for(i = 0; i < N; i++)
{
x = XS + random() * (XE - XS);
y = f_i(x);
cout << "x = "
<< setw(7) << x
<< ", f(x) = "
<< setw(7) << f(x)
<< ", interpolacja f(x) = "
<< setw(7) << y
<< endl;
}
}
else
cout <<
"Błąd w trakcie obliczeń!!!\n";
cout << endl;
system("pause");
return 0;
}
|
| Wynik: |
Interpolacja wielomianowa ------------------------- x = 1.3609, f(x) = 0.9781, interpolacja f(x) = 0.9780 x = 0.0129, f(x) = 0.0129, interpolacja f(x) = 0.0129 x = -0.1596, f(x) = -0.1590, interpolacja f(x) = -0.1589 x = -0.1612, f(x) = -0.1605, interpolacja f(x) = -0.1605 x = -1.5022, f(x) = -0.9977, interpolacja f(x) = -0.9975 x = 1.1324, f(x) = 0.9054, interpolacja f(x) = 0.9056 x = -0.4658, f(x) = -0.4491, interpolacja f(x) = -0.4491 x = -0.5882, f(x) = -0.5549, interpolacja f(x) = -0.5549 x = -0.7689, f(x) = -0.6954, interpolacja f(x) = -0.6954 x = -1.3818, f(x) = -0.9822, interpolacja f(x) = -0.9820 |
Python
(dodatek) # Interpolacja wielomianowa
# (C)2026 mgr Jerzy Wałaszek
# Metody numeryczne 0074
#---------------------------
from math import sin, pi
from random import uniform
# STAŁE
#------
# Przedział interpolacji
# od XS do XE
XS = -pi / 2
XE = pi / 2
# liczba węzłów
NN = 6
# Liczba interpolowanych
# punktów
N = 10
# Dokładność przyrównania do 0
EPS = 0.00001
# Tablice
#--------
# Współrzędne x węzłów
nx = []
# Współrzędne y węzłów
ny = []
# Współczynniki wielomianu
a = [0.0 for _ in range(NN)]
# Funkcje
#--------
# Funkcja interpolowana
#----------------------
def f(x):
return sin(x)
# Funkcja wyznacza węzły
# dla wielomianu
#-----------------------
def set_nodes():
# Dwa pierwsze węzły
# definiują przedział
# interpolacji
nx.append(XS)
nx.append(XE)
# Pozostałe punkty są
# rozsiane po przedziale
# Minimalna odległość w osi OX
# pomiędzy węzłami
dx = (XE - XS) / 2 / NN
while(len(nx) < NN):
xx = uniform(XS,XE)
t = False
for j in nx:
# Sprawdzamy odległość
# węzłów w osi OX
if abs(xx - j) < dx:
t = True
break
# Węzeł za blisko innego,
# losujemy go ponownie
if t: continue
nx.append(xx)
# Dla współrzędnych x
# liczymy współrzędne y
for i in nx:
ny.append(f(i))
# Oblicza wartość wielomianu
#---------------------------
def f_i(x):
# Współczynnik przy x^(NN-1)
w = a[NN - 1]
for i in range(NN - 1, 0,-1):
w *= x
w += a[i-1]
return w
# Funkcja rozwiązuje układ równań
# metodą eliminacji Gaussa
# NN - stopień macierzy
# AB - macierz rozszerzona NN x (NN + 1)
# X - macierz rozwiązań NN x 1
# Jeśli układ został rozwiązany,
# to wynikiem jest true.
# Inaczej wynikiem jest false.
#--------------------------------
def gaussCrout(ab,x):
# Przygotowujemy wektor
# kolumnowy
wk = [_ for _ in range(NN + 1)]
# Eliminacja
for i in range(NN - 1):
k = i
for j in range(i + 1, NN):
if (abs(ab[i][wk[k]]) <
abs(ab[i][wk[j]])):
k = j
if k != i:
wk[k],wk[i] = wk[i],wk[k]
if abs(ab[i][wk[i]]) < EPS:
return False
for j in range(i + 1, NN):
m = (-ab[j][wk[i]] /
ab[i][wk[i]])
for k in range(i + 1, NN + 1):
ab[j][wk[k]] += (m *
ab[i][wk[k]])
# Obliczanie wartości niewiadomych
for i in reversed(range(NN)):
if abs(ab[i][wk[i]]) < EPS:
return False
s = ab[i][NN]
for j in reversed(range(i + 1, NN)):
s -= ab[i][wk[j]] * x[wk[j]]
x[wk[i]] = s / ab[i][wk[i]]
return True
# Program główny
#---------------
# Generujemy węzły
set_nodes()
# Tworzymy macierz
# układu równań
ab = [[0.0 for _ in range(NN + 1)]
for _ in range(NN)]
for i in range(NN):
# W ostatniej kolumnie
# są współrzędne y
ab[i][NN] = ny[i]
# W pierwszej są 1
ab[i][0] = 1
# Pozostałe są potęgami
for j in range(1, NN):
ab[i][j] = nx[i] * ab[i][j-1]
# Wyznaczamy współczynniki
# wielomianu
if gaussCrout(ab,a):
print("Interpolacja wielomianowa\n"
"-------------------------\n")
# Generujemy N punktów x
# i liczymy dla nich y
# przy pomocy wielomianu
# i wyświetlamy wynik
for i in range(N):
x = uniform(XS, XE)
y = f_i(x)
print(f"x = {x:7.4f}"
f", f(x) = {f(x):7.4f}"
f", interpolacja f(x) = "
f"{y:7.4f}")
else:
print("Błąd w trakcie obliczeń!!!")
print()
input("Naciśnij Enter...")
|
Dla funkcji y = sin(x) otrzymaliśmy bardzo ładne wyniki, ale z innymi funkcjami tak pięknie być nie musi. Interpolacja wielomianowa jest niestabilna numerycznie i przy większej liczbie węzłów może pojawić się efekt Rungego. Istnieją lepsze metody interpolacji i kilka z nich przedstawimy w następnych rozdziałach.
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.