Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
73
Добавлен:
02.05.2014
Размер:
129.54 Кб
Скачать

Алгоритм построения интерполяционного кубического сплайна

Пусть каждому значению аргумента xi, i=0,...,n соответствуют значения функции f(xi)=yi и требуется найти функциональную зависимость в виде сплайна (1.1), удовлетворяющего перечисленным ниже требованиям:

а) функция S3(xi) непрерывна вместе со своими производными до второго порядка включительно;

б) S3(xi)=yi, i=0,1,...,n;

в) S"3(x0)=S"3(xn)=0.

Сформулированная выше задача имеет единственное решение.

Вторая производная S"3(x) непрерывна и, как видно из выражения (1.1), линейна на каждом отрезке [xi-1, xi], (i=1,...,n), поэтому представим ее в виде

, (1.4)

где hi = xi- xi-1 , mi= S"3(xi).

Интегрируя обе части равенства (1.4), получим

, (1.5)

где Ai и Bi - постоянные интегрирования.

Пусть в (1.5) x=xi и x=xi-1, тогда используя условия б), получим

, i=1,...,n.

Из этих уравнений находим Ai и Bi, и окончательно формула (1.5) принимает вид

. (1.6)

Из формулы (1.6) находим односторонние пределы производной в точках x1,x2 ,...,xn-1:

, (1.7)

. (1.8)

Приравнивая выражения (1.7) и (1.8) для i=1,...,n-1, получим n-1 уравнение

(1.9)

с n-1 неизвестными mi (i=1,...,n-1). Согласно условию (1.4) m0=mn=0.

Система линейных алгебраических уравнений (1.9) имеет трехдиагональную матрицу с диагональным преобладанием. Такие матрицы являются неособенными. Поэтому неизвестные m1 , m2 , ... , mn-1 находятся из системы (1.9) однозначно. Они могут быть найдены итерационными и прямыми методами решения систем линейных алгебраических уравнений, в том числе и методом прогонки. После определения mi функция S3(x) восстанавливается по формуле (1.6).

Метод прогонки

Пусть имеется система уравнений, записанная в матричном виде:

. (1.10)

В нашем случае согласно (1.9)

Решение системы ищется в виде

mi = i mi+1 + i , i=1,...,N-1, (1.11)

где Ai , Bi - прогоночные коэффициенты. Используя выражение для m i-1 из (1.11), исключим это неизвестное из i‑го уравнения системы. Получаем

(ai +ci i-1)mi + bi mi+1 = di -cii-1.

Сравнивая это соотношение с (1.11), выводим рекуррентные формулы для прогоночных коэффициентов i, i (прямая прогонка):

0=0=0, . (1.12)

Очевидно, что mn-1=n-1 (при сn-1=0). Все остальные неизвестные находим по формулам (1.11), используя выражения для прогоночных коэффициентов (1.12).

Для реализации алгоритма требуется выполнить 8(n-1) арифметических операций: 3(n-1) сложений, 3(n-1) умножений, 2(n-1) делений.

Величины i и ai +cii-1 не зависят от правой части системы. Поэтому если вычислить их и запомнить, то для решения систем, отличающихся только правыми частями, потребуется 5(n-1) арифметических операций.

Листинг программы:

#include <stdio.h>

#include <windows.h>

#include <iostream.h>

#include <stdlib.h>

float d[99999];

float l[99999];

float m[99999];

double f[99999];

float s[99999],mu[99999];

void main()

{

system("cls");

int n;

float c,a,b,shag;

float h;

cout<<"Vvedite shag h:=";

cin>>h;

cout<<"Vvedite kolichestvo znachenii n:=";

cin>>n;

shag=h/2;

c=h/6;

a=2*h/3;

b=h/6;

cout<<"c="<<c<<" a="<<a<<" b="<<b<<endl;

int i;

float x[99999],y[99999];

for(i=1;i<n+1;i++)

{

x[i]=(float)i;

}

for(i=1;i<n+1;i++)

{

cout<<"Vvedite Y["<<h*i<<"]:=";

cin>>y[i];

}

mu[0]=m[0]=m[n]=l[0]=0;

for(i=2;i<n+1;i++)

{

d[i]=((y[1+i]-y[i])/h)-(y[i]-y[i-1])/h;

}

for(i=1;i<n+1;i++)

{

l[i]=-b/(a+c*l[i-1]);

mu[i]=(d[i]-c*mu[i-1])/(a+c*l[i-1]);

}

for(i=n-1;i>1;i--)

{

m[i]=l[i]*m[i+1]+mu[i];

}

double po;

for(i=2;i<n;i++)

{

f[i]=x[i]-shag;

s[i]=(((x[i]-f[i])*y[i-1])/h)+(((f[i]-x[i-1])*y[i])/h)+(((x[i]-f[i])*(x[i]-f[i])*(x[i]-f[i]))-((h)*(h)*(x[i]-f[i]))*(m[i-1]))/(6*h)+((((f[i]-x[i-1])*(f[i]-x[i-1])*(f[i]-x[i-1]))-(h)*(h)*(f[i]-x[i-1]))*m[i])/(6*h);

po=(float)(h*i);

po=po-shag;

cout<<"S["<<po<<"]="<<s[i]<<endl;

po=(float)(h*i);

cout<<"S["<<po<<"]= "<<y[i]<<endl;

}

system("PAUSE");

}

Проверим правильность выполнения программы на примере функции y(x)=sinx, в качестве узловых точек возьмем точки из интервала (0;Π] с шагом h=Π/8. Найдем значения функции в промежуточных точках при помощи интерполяции функции сплайном:

Пример

Vvedite shag h:=0.3925

Vvedite kolichestvo znachenii n:=8

c=0.0654167 a=0.261667 b=0.0654167

Vvedite Y[0.3925]:=0.38249949727

Vvedite Y[0.785]:=0.7068251811

Vvedite Y[1.1775]:=0.92365

Vvedite Y[1.57]:=0.999999

Vvedite Y[1.9625]:=0.9246

Vvedite Y[2.355]:=0.70795

Vvedite Y[2.7475]:=0.38397

Vvedite Y[3.14]:=0.00159

S[0.58875]=1.49443

S[0.785]= 0.706825

S[0.98125]=2.10928

S[1.1775]= 0.92365

S[1.37375]=2.35328

S[1.57]= 0.999999

S[1.76625]=2.25135

S[1.9625]= 0.9246

S[2.15875]=1.80784

S[2.355]= 0.70795

S[2.55125]=1.087

S[2.7475]= 0.38397

Для продолжения нажмите любую клавишу . . .

Вывод: Как мы видим, значения функции, полученные нами в промежуточных точках, не совпадают с теоретическими значениями, это вызвано тем, что функция y(x)=sinx является периодической, что влечет собой достаточно большую погрешность при интерполировании.

Проверим также метод интерполяции на более монотонной функции, например на функции y(x)=x2. В качестве узловых точек возьмем точки из отрезка [1;8], с шагом h=1:

Vvedite shag h:=1

Vvedite kolichestvo znachenii n:=8

c=0.166667 a=0.666667 b=0.166667

Vvedite Y[1]:=1

Vvedite Y[2]:=4

Vvedite Y[3]:=9

Vvedite Y[4]:=16

Vvedite Y[5]:=25

Vvedite Y[6]:=36

Vvedite Y[7]:=49

Vvedite Y[8]:=64

S[1.5]=2.35101

S[2]= 4

S[2.5]=6.18125

S[3]= 9

S[3.5]=12.2424

S[4]= 16

S[4.5]=20.2242

S[5]= 25

S[5.5]=30.2359

S[6]= 36

S[6.5]=42.2074

S[7]= 49

Для продолжения нажмите любую клавишу . . .

Вывод: Как мы можем заметить, при интерполировании более монотонной функции, погрешность расчетов оказалось относительно небольшой.

Соседние файлы в папке Лабораторные работы1