|
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 |
Zadaniem interpolacji jest znalezienie wartości pośrednich pomiędzy wartościami znanymi. Aby zrozumieć, jak to działa, załóżmy, że mamy do czynienia z pewną funkcją:

Załóżmy dalej, że udało nam się zmierzyć wartość tej funkcji w dwóch punktach: (x0,y0) i (x1,y1):

Łączymy te punkty odcinkiem:

Odcinek przybliża funkcję f(x) pomiędzy punktami (x0,y0) i (x1,y1). Załóżmy teraz, iż mamy pewne x, które leży pomiędzy x0 i x1. Chcemy znaleźć przybliżoną wartość funkcji f(x) dla tej współrzędnej x. W tym celu znajdziemy na odcinku punkt (x,y) o współrzędnej x:

Wykorzystamy tutaj geometrię. Utwórzmy dwa trójkąty prostokątne:

Zewnętrzny trójkąt mający boki a i b (a - podstawa, b - wysokość) oraz wewnętrzny z bokami c i d (c - podstawa, d - wysokość). Przeciwprostokątne tych trójkątów leżą na odcinku łączącym punkty (x0,y0) i (x1,y1). Zapiszmy wzory na długości tych boków:

Ponieważ trójkąty są podobne, możemy ułożyć proporcję:

W proporcji nieznana jest wartość d (wysokość trójkąta wewnętrznego), zatem liczymy ją:

Podstawiamy wzory na długości boków:

Otrzymujemy podstawowy wzór interpolacji liniowej:
![]() |
W pierwszym programie wykorzystamy otrzymany wzór interpolacyjny do wyznaczenia 10 wartości funkcji f(x) = sin(x) w przedziale domkniętym <0;π/2>. Wyjaśnienie znajdziesz w komentarzach w programie.

C++// Interpolacja liniowa
// (C)2026 mgr Jerzy Wałaszek
// Metody numeryczne 0071
//---------------------------
#include <iostream>
#include <windows.h>
#include <iomanip>
#define _USE_MATH_DEFINES
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
// Stałe
//------
// Liczba interpolowanych
// punktów
const int N = 10;
// Przedział interpolacji
// od XS do XE
const double XS = 0;
const double XE = M_PI / 2;
// Funkcja oblicza wartość
// interpolowanej funkcji
// na podstawie jej przepisu
//--------------------------
double f(double x)
{
return sin(x);
}
// Funkcja oblicza
// wartość interpolowaną
//----------------------
double f_i(double x0,
double y0,
double x1,
double y1,
double x)
{
return y0 + (y1 - y0) /
(x1 - x0) * (x - x0);
}
// Funkcja zwraca wartość
// pseudolosową w przedziale <0,1)
//--------------------------------
double random()
{
return rand() / ((double)RAND_MAX + 1);
}
// Program główny
//---------------
int main()
{
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
cout << setprecision(4)
<< fixed;
// Inicjujemy generator
// pseudolosowy
srand(time(nullptr));
// Generujemy tablicę
// N współrzędnych x
// w przedziale <XS,XE>
double x[N], y[N];
int i;
for(i = 0; i < N; i++)
x[i] = XS + random() * (XE - XS);
// Punkty krańcowe
double x0 = XS;
double y0 = f(x0);
double x1 = XE;
double y1 = f(x1);
// obliczamy współrzędne y
for(i = 0; i < N; i++)
y[i] = f_i(x0,y0,x1,y1,x[i]);
// Wyświetlamy wyniki:
cout << "Interpolacja liniowa\n"
"--------------------\n\n";
for(i = 0; i < N; i++)
cout << "x = "
<< setw(7) << x[i]
<< ", f(x) = "
<< setw(7) << f(x[i])
<< ", interpolacja f(x) = "
<< setw(7) << y[i]
<< endl;
cout << endl;
system("pause");
return 0;
}
|
| Wynik |
Interpolacja liniowa -------------------- x = 1.0280, f(x) = 0.8563, interpolacja f(x) = 0.6544 x = 0.4897, f(x) = 0.4704, interpolacja f(x) = 0.3118 x = 0.6477, f(x) = 0.6034, interpolacja f(x) = 0.4124 x = 0.0000, f(x) = 0.0000, interpolacja f(x) = 0.0000 x = 1.1749, f(x) = 0.9226, interpolacja f(x) = 0.7480 x = 1.4669, f(x) = 0.9946, interpolacja f(x) = 0.9338 x = 1.0993, f(x) = 0.8909, interpolacja f(x) = 0.6999 x = 0.1452, f(x) = 0.1447, interpolacja f(x) = 0.0924 x = 0.5621, f(x) = 0.5329, interpolacja f(x) = 0.3578 x = 0.2935, f(x) = 0.2893, interpolacja f(x) = 0.1869 |
Python
(dodatek) # Interpolacja liniowa
# (C)2026 mgr Jerzy Wałaszek
# Metody numeryczne 0071
#---------------------------
from math import sin,pi
from random import random
# Stałe
#------
# Liczba interpolowanych
# punktów
N = 10
# Przedział interpolacji
# od XS do XE
XS = 0
XE = pi / 2
# Funkcja oblicza wartość
# interpolowanej funkcji
# na podstawie jej przepisu
#--------------------------
def f(x):
return sin(x)
# Funkcja oblicza
# wartość interpolowaną
#----------------------
def f_i(x0,y0,x1,y1,x):
return (y0 + (y1 - y0) /
(x1 - x0) * (x - x0))
# Program główny
#---------------
# Punkty krańcowe
x0 = XS
y0 = f(x0)
x1 = XE
y1 = f(x1)
# Generujemy tablice
# N współrzędnych x
# w przedziale <XS,XE>
# oraz interpolowanych
# wartości funkcji f()
# dla współrzędnych x
x = []
y = []
for i in range(N):
x.append(XS + random() * (XE - XS))
y.append(f_i(x0,y0,x1,y1,x[i]))
# Wyświetlamy wyniki:
print("Interpolacja liniowa\n"
"--------------------\n")
for i in range(N):
print(f"x = {x[i]:7.4f}"
f", f(x) = {f(x[i]):7.4f}"
f", interpolacja f(x) = "
f"{y[i]:7.4f}")
print()
input("Naciśnij Enter...")
|
Gdy przeglądniesz wyniki, zauważysz iż wyznaczone wartości są obarczone błędami interpolacji (dla f(x) = sin(x) do 1/3 wartości f(x)). Dokładność można zwiększyć dodając w przedziale interpolacji nowe węzły interpolacyjne (węzeł interpolacyjny to punkt, w którym wartość funkcji zrównuje się z wartością interpolowaną):
W tym przypadku przedział <0;π/2> podzieliliśmy na dwa przedziały:
| <x0;x1>
= <0;π/4> <x1;x2> = <π/4;π/2> |
Obliczamy wartość funkcji na krańcach tych przedziałów i otrzymujemy:
| y0 = sin(x0)
= sin(0) y1 = sin(x1) = sin(π/4) y2 = sin(x2) = sin(π/2) |
Dostajemy trzy węzły interpolacyjne:
| P0 = (x0,y0) P1 = (x1,y1) P2 = (x2,y2) |
Kolejne węzły interpolacyjne łączymy odcinkami i otrzymujemy łamaną, która lepiej przybliża przebieg funkcji niż pierwotny pojedynczy odcinek:

Prześledźmy algorytm interpolacji wielowęzłowej. Mamy pewną funkcję y = f(x):

Określamy przedział interpolacji: <xs;xe>, w którym będziemy interpolować wartości funkcji f(x) dla x z tego przedziału:

Przedział <xs;xe> dzielimy na nn równych segmentów:

Segmenty mają stałą długość dx:

Jeśli segmenty interpolacji mają stałą długość dx, to współrzędnych xi, i = 0,1,...,nn nie musimy wcale zapamiętywać, ponieważ można je łatwo wyliczyć na podstawie ich numeru:

Oczywiście, jeśli mamy interpolować wiele wartości funkcji f(x), to wyznaczone punkty xi zapamiętujemy, w celu przyspieszenia obliczeń.
Dla każdej współrzędnej xi, i = 0,1,...,nn musimy posiadać wartości funkcji yi = f(xi):

Otrzymujemy w ten sposób węzły interpolacyjne, które łączymy odcinkami i dostajemy łamaną, która przybliża przebieg funkcji:

Po tym etapie przygotowawczym jesteśmy gotowi do wykonania interpolacji. Mamy zatem pewne x ∈ <xs;xe>. Zaczynamy od znalezienia segmentu <xi;xi+1>, i = 0,1,...,nn-1, takiego że:

Jeśli punkty xi są rozłożone równomiernie w przedziale interpolacji, to numer i możemy wyliczyć korzystając z szerokości segmentu dx:

Mając numer segmentu, możemy obliczyć wartość interpolowaną funkcji dla argumentu x:

Kolejny program interpoluje liniowo funkcję y = sin(x) w przedziale domkniętym <-π;π>. Wykonuje on następujące operacje:
C++// Interpolacja liniowa
// (C)2026 mgr Jerzy Wałaszek
// Metody numeryczne 0072
//---------------------------
#include <iostream>
#include <windows.h>
#include <iomanip>
#define _USE_MATH_DEFINES
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
// Stałe
//------
// Liczba węzłów
// interpolacyjnych
const int NN = 50;
// Liczba punktów
// interpolowanych
const int N = 10;
// Krańce przedziału
// interpolacji
const double XS = -M_PI;
const double XE = M_PI;
// Tablice współrzędnych
// węzłów interpolacji
double nx[NN+1], ny[NN+1];
// Szerokość segmentu
const double DX = (XE - XS) / NN;
// Interpolowana funkcja
//----------------------
double f(double x)
{
return sin(x);
}
// Zwraca liczbę
// pseudolosową <0,1)
//-------------------
double random()
{
return rand() /
(double)(RAND_MAX + 1);
}
// Przygotowuje tablice
// nx[] i ny[]
//---------------------
void setnn()
{
int i;
for(i = 0; i <= NN; i++)
{
nx[i] = XS + i * DX;
ny[i] = f(nx[i]);
}
}
// Oblicza wartość
// interpolowaną
//----------------
double f_i(double x0,
double y0,
double x1,
double y1,
double x)
{
return y0 + (y1 - y0) /
(x1 - x0) * (x - x0);
}
// Program główny
//---------------
int main()
{
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
cout << setprecision(4)
<< fixed;
// Inicjujemy generator
// pseudolosowy
srand(time(nullptr));
// Przygotowujemy tablice
// nx[] i ny[]
setnn();
// Generujemy tablicę
// N współrzędnych x
// w przedziale <XS,XE>
double x[N], y[N];
int i,j;
for(j = 0; j < N; j++)
{
x[j] = XS + random() *
(XE - XS);
// Wyznaczamy segment
i = floor((x[j] - XS) / DX);
// Wartość interpolowana
// funkcji
y[j] = f_i(nx[i],ny[i],
nx[i+1],ny[i+1],
x[j]);
}
// Wyświetlamy wyniki:
cout <<
"Interpolacja liniowa\n"
"--------------------\n\n";
for(i = 0; i < N; i++)
cout << "x = "
<< setw(7) << x[i]
<< ", f(x) = "
<< setw(7) << f(x[i])
<< ", interpolacja f(x) = "
<< setw(7) << y[i]
<< endl;
cout << endl;
system("pause");
return 0;
}
|
| Wynik |
Interpolacja liniowa -------------------- x = 0.6926, f(x) = 0.6385, interpolacja f(x) = 0.6373 x = -2.4900, f(x) = -0.6064, interpolacja f(x) = -0.6057 x = 3.0051, f(x) = 0.1361, interpolacja f(x) = 0.1360 x = -1.7673, f(x) = -0.9807, interpolacja f(x) = -0.9803 x = 0.7369, f(x) = 0.6720, interpolacja f(x) = 0.6714 x = -0.4732, f(x) = -0.4558, interpolacja f(x) = -0.4551 x = -0.5981, f(x) = -0.5630, interpolacja f(x) = -0.5623 x = 0.1419, f(x) = 0.1414, interpolacja f(x) = 0.1413 x = 1.2535, f(x) = 0.9501, interpolacja f(x) = 0.9499 x = 2.9176, f(x) = 0.2221, interpolacja f(x) = 0.2218 |
Zwróć uwagę, iż teraz wartości interpolowane lepiej zgadzają się z wartościami funkcji. Zwiększ liczbę węzłów interpolacji NN, np. do 1000. Tego typu rozwiązania pozwalają obliczać wartości funkcji na podstawie jej znanych wartości.
Python
(dodatek) # Interpolacja liniowa
# (C)2026 mgr Jerzy Wałaszek
# Metody numeryczne 0072
#---------------------------
from math import sin, pi, floor
from random import random
# Stałe
#------
# Liczba węzłów
# interpolacyjnych
NN = 50
# Liczba punktów
# interpolowanych
N = 10
# Krańce przedziału
# interpolacji
XS = -pi
XE = pi
# Tablice współrzędnych
# węzłów interpolacji
nx = []
ny = []
# Szerokość segmentu
DX = (XE - XS) / NN
# Interpolowana funkcja
#----------------------
def f(x):
return sin(x)
# Przygotowuje tablice
# nx[] i ny[]
#---------------------
def setnn():
for i in range(NN + 1):
nx.append(XS + i * DX)
ny.append(f(nx[i]))
# Oblicza wartość
# interpolowaną
#----------------
def f_i(x0, y0, x1, y1, x):
return (y0 + (y1 - y0) /
(x1 - x0) * (x - x0))
# Program główny
#---------------
# Przygotowujemy tablice
# nx[] i ny[]
setnn()
# Generujemy tablicę
# N współrzędnych x
# w przedziale <XS,XE>
x = []
y = []
for j in range(N):
x.append(XS + random() * (XE - XS))
# Wyznaczamy segment
i = int(floor((x[j] - XS) / DX))
# Wartość interpolowana
# funkcji
y.append(f_i(nx[i],ny[i],
nx[i+1],ny[i+1],
x[j]))
# Wyświetlamy wyniki:
print("Interpolacja liniowa\n"
"--------------------\n")
for i in range(N):
print(f"x = {x[i]:7.4f}"
f", f(x) = "
f"{f(x[i]):7.4f}"
f", interpolacja f(x) = "
f"{y[i]:7.4f}")
print()
input("Naciśnij Enter...")
|
Jeśli dane węzłów interpolacji pochodzą np. z czujników, to wcale nie muszą tworzyć węzłów równoodległych, ani nie muszą być uporządkowane. Algorytm interpolujący należy wtedy zmodyfikować.
Procedura jest następująca:
Trzeci program działa wg powyższej procedury. Wyjaśnienia są w komentarzach.
C++// Interpolacja liniowa
// (C)2026 mgr Jerzy Wałaszek
// Metody numeryczne 0073
//---------------------------
#include <iostream>
#include <windows.h>
#include <iomanip>
#define _USE_MATH_DEFINES
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
// Stałe
//------
// Liczba segmentów
// interpolacyjnych
const int NN = 50;
// Liczba punktów
// interpolowanych
const int N = 10;
// Krańce przedziału
// interpolacji
const double XS = -M_PI;
const double XE = M_PI;
// Tablice współrzędnych
// węzłów interpolacji
double nx[NN+1], ny[NN+1];
// Interpolowana funkcja
//----------------------
double f(double x)
{
return sin(x);
}
// Zwraca liczbę
// pseudolosową <0,1)
//-------------------
double random()
{
return rand() / (double)(RAND_MAX + 1);
}
// Funkcja porównująca dla
// qsort()
//------------------------
int cmp(const void * a,
const void * b)
{
double da = *(const double*)a;
double db = *(const double*)b;
if (da < db) return -1;
if (da > db) return 1;
return 0;
}
// Przygotowuje tablice nx[] i ny[]
//---------------------------------
void setnn()
{
int i;
// Dwa pierwsze punkty to węzły początkowy
// i końcowy
nx[0] = XS;
nx[1] = XE;
// Pozostałe punkty to węzły pośrednie
for(i = 2; i <= NN; i++)
nx[i] = XS + random() * (XE - XS);
// Porządkujemy rosnąco
// współrzędne x węzłów
qsort((void *)nx, // tablica
(size_t)NN+1, // ilość elem.
sizeof(double),// rozmiar elem.
cmp); // funkcja porówn.
// Teraz wyznaczamy współrzędne y dla
// uporządkowanych współrzędnych x
for(i = 0; i <= NN; i++)
ny[i] = f(nx[i]);
}
// Oblicza wartość interpolowaną
//------------------------------
double f_i(double x0,
double y0,
double x1,
double y1,
double x)
{
return y0 + (y1 - y0) /
(x1 - x0) * (x - x0);
}
// Program główny
//---------------
int main()
{
SetConsoleOutputCP(CP_UTF8);
SetConsoleCP(CP_UTF8);
cout << setprecision(4)
<< fixed;
// Inicjujemy generator
// pseudolosowy
srand(time(nullptr));
// Przygotowujemy tablice
// nx[] i ny[]
setnn();
// Generujemy tablicę N współrzędnych x
// do interpolowania w przedziale <XS,XE>
double x[N], y[N];
int i,j;
for(j = 0; j < N; j++)
{
x[j] = XS + random() * (XE - XS);
// Wyznaczamy segment, w którym
// jest interpolowany punkt
for(i = 0; nx[i] < x[j]; i++);
i--;
// interpolujemy
y[j] = f_i(nx[i],ny[i],
nx[i+1],ny[i+1],
x[j]);
}
// Wyświetlamy wyniki:
cout <<
"Interpolacja liniowa\n"
"--------------------\n\n";
for(i = 0; i < N; i++)
cout << "x = "
<< setw(7) << x[i]
<< ", f(x) = "
<< setw(7) << f(x[i])
<< ", interpolacja f(x) = "
<< setw(7) << y[i]
<< endl;
cout << endl;
system("pause");
return 0;
}
|
| Wynik |
Interpolacja liniowa -------------------- x = 1.2856, f(x) = 0.9596, interpolacja f(x) = 0.9590 x = -0.9119, f(x) = -0.7906, interpolacja f(x) = -0.7850 x = -0.5975, f(x) = -0.5625, interpolacja f(x) = -0.5621 x = 3.1103, f(x) = 0.0312, interpolacja f(x) = 0.0310 x = 2.2525, f(x) = 0.7765, interpolacja f(x) = 0.7762 x = -1.7463, f(x) = -0.9846, interpolacja f(x) = -0.9792 x = 0.6460, f(x) = 0.6020, interpolacja f(x) = 0.6006 x = -1.8863, f(x) = -0.9506, interpolacja f(x) = -0.9417 x = 0.3373, f(x) = 0.3309, interpolacja f(x) = 0.3218 x = -1.3839, f(x) = -0.9826, interpolacja f(x) = -0.9804 |
Python
(dodatek) # Interpolacja liniowa
# (C)2026 mgr Jerzy Wałaszek
# Metody numeryczne 0073
#---------------------------
from random import random
from math import pi,sin
# Stałe
#------
# Liczba segmentów
# interpolacyjnych
NN = 50
# Liczba punktów
# interpolowanych
N = 10
# Krańce przedziału
# interpolacji
XS = -pi
XE = pi
# Tablice współrzędnych
# węzłów interpolacji
nx = []
ny = []
# Interpolowana funkcja
#----------------------
def f(x):
return sin(x)
# Przygotowuje tablice
# nx[] i ny[]
#---------------------
def setnn():
# Dwa pierwsze punkty
# to węzły początkowy
# i końcowy
nx.append(XS)
nx.append(XE)
# Pozostałe punkty
# to węzły pośrednie
for _ in range(2,NN+1):
nx.append(XS + random() *
(XE - XS))
# Porządkujemy rosnąco
# współrzędne x węzłów
nx.sort()
# Teraz wyznaczamy
# współrzędne y dla
# uporządkowanych
# współrzędnych x
for s in nx:
ny.append(f(s))
# Oblicza wartość interpolowaną
#------------------------------
def f_i(x0, y0, x1, y1, x):
return (y0 + (y1 - y0) /
(x1 - x0) * (x - x0))
# Program główny
#---------------
# Przygotowujemy tablice
# nx[] i ny[]
setnn()
# Generujemy tablicę
# N współrzędnych x
# do interpolowania
# w przedziale <XS,XE>
x = [XS + random() * (XE - XS)
for _ in range(N)]
y = []
for j in range(N):
# Wyznaczamy segment, w którym
# jest interpolowany punkt
i = 0
while i < NN and nx[i] < x[j]:
i += 1
i -= 1
# interpolujemy
y.append(f_i(nx[i],ny[i],
nx[i+1],ny[i+1],x[j]))
# Wyświetlamy wyniki:
print("Interpolacja liniowa\n"
"--------------------\n")
for i in range(N):
print(f"x = {x[i]:7.4f}"
f", f(x) = {f(x[i]):7.4f}"
f", interpolacja f(x) = "
f"{y[i]:7.4f}")
print()
input("Naciśnij Enter...")
|
![]() |
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.