Числові методи
МІНІСТЕРСТВО
ОСВІТИ УКРАЇНИ
ЧЕРНІВЕЦЬКИЙ
ДЕРЖАВНИЙ УНІВЕРСИТЕТ
ІМ. Ю.
ФЕДЬКОВИЧА
КОНТРОЛЬНА
РОБОТА
з
дисципліни " Числові методи "
Варіант
16.
Виконав
студент 2-го курсу
кафедри ЕОМ
Перевірив
м. Чернівці
Завдання 1
Задана СЛАР
а) розв’язати цю
систему методом Гауса за схемою з частковим вибором головного елементу;
б)розв’язати цю
систему за формулою
.
– вектор невідомих, –
вектор вільних членів, – обернена матриця до матриці з коєфіцієнтів при невідомих.
Обернену матрицю
знай ти методом Гауса - Жордана за схемою з частковим вибором головного
елемента.
Рішення.
а) Прямий хід
методу Гауса.
()
Запишемо матрицю .
1-й крок.
Серед елементів
першого стовпчика шукаємо максимальний:
Перше і друге
рівняння міняємо місцями.
Розділимо
рівняння (1) на 2.5
(1)
Від рівняння (2)
віднімемо 1.7Р1 .
(2)
(3)
Таким чином в
кінці першого кроку отримуємо систему
2-й крок.
Порядок рівнянь
зберігається.
(2)
(3)
Після другого
кроку система рівнянь стала такою:
Зворотній хід.
З рівняння (3) ;
з рівняння (2) ;
з рівняння (1) ;
Для рішення системи
лінійних рівнянь методом Гауса призначена програма Work1_1.
//------------------------------------------------------------
// Work1_1.cpp
//------------------------------------------------------------
// "Числові
методи"
// Завдання 1
// Рішення
системи лінійних рівнянь методом Гауса
#include
<stdio.h>
#include
<iostream.h>
#include
<conio.h>
const int nMax=5;
// максимальна кількість рівнянь
const float
ZERO=.0000001;
int fGaus(float
A[nMax][nMax],float B[nMax],int n,float X[nMax])
/* Функція
розв'язує систему лінійних рівнянь методом Гауса за схемою з
частковим вибором
головного елементу.
Вхідні дані:
A- масив з
коефіцієнтами при невідомих;
В- масив з
вільними членами СЛАР;
n- порядок
матриці А(кількість рівнянь системи);
Вихідні дані:
Х- масив з
коренями системи;
функція повертає
код помилки:
0- сисетма
успішно розв’язана;
1- матриця А
вироджена. */
{float aMax,t; //
максимальний елемент , тимчасова змінна
int i,j,k,l;
for(k=0; k<n;
k++) // шукаємо головний елемент, мах за модулем
{aMax=A[k][k]; l=k;
for (i=k+1;
i<n; i++)
if
(fabs(A[i][k])>fabs(aMax))
{aMax=A[i][k];
l=i;}
// якщо модуль
головного елементу aMax менший за програмний 0 (ZERO)
if ( fabs(aMax)<ZERO
) return 1;
// якщо потрібно,
міняємо місцями рівняння Pk i Pl
if ( l!=k)
{for( j=0;
j<n; j++)
{ t=A[l][j]; A[l][j]=A[k][j];
A[k][j]=t; }
t=B[l];
B[l]=B[k]; B[k]=t;}
// ділимо k-те
рівняння на головний елемент
for (j=0; j<n;
j++) A[k][j]/=aMax;
B[k]/=aMax;
// обчислюємо коефіцієнти
A[i][j] та вільні члени решти рівнянь
for (i=k+1;
i<n; i++)
{t=A[i][k];
B[i]-=t*B[k];
for (j=0; j<n;
j++) A[i][j]-=t*A[k][j];}
} // for (k)
// Зворотній хід
for ( k=n-1;
k>=0; k--)
{X[k]=0;
for (l=k+1;
l<n; l++) X[k]+=A[k][l]*X[l];
X[k]=B[k]-X[k];}
return 0;
} // fGaus()
void main()
{float
A[nMax][nMax];
float B[nMax];
float X[nMax];
int n,i,j;
char
*strError="\n Error of file !";
FILE
*FileIn,*FileOut;
FileIn=fopen("data_in.txt","r");
// відкриваємо файл для читання
if (FileIn==NULL)
{cout <<
" \"Data_in.txt\": Error open file or file not found
!!!\n";
goto exit;}
FileOut=fopen("data_out.txt","w");
// відкриваємо файл для запису
if
(FileOut==NULL)
{cout <<
" \"Data_out.txt\": Error open file !!!\n";
goto exit;}
if(fscanf(FileIn,"%d",&n)==NULL)
{ cout <<
strError; goto exit;};
for (i=0; i<n;
i++)
for(j=0; j<n;
j++)
fscanf(FileIn,"%f",&(A[i][j]));
for (i=0;
i<n;i++)
if(fscanf(FileIn,"%f",&(B[i]))==NULL)
{ cout <<
strError; goto exit;}
if(fGaus(A,B,n,X)!=0)
{ cout <<
"\n det|A|=0 !"; goto exit;}
// Вивід
результатів
for (i=0; i<n;
i++)
{printf("
x[%d]= %f ",i+1,X[i]);
fprintf(FileOut,"
x[%d]= %f ",i+1,X[i]);}
fclose(FileIn);
fclose(FileOut);
exit: cout
<< "\n Press any key ...";
getch();}
Результат роботи
програми:
x[1]= 3.017808 x[2]=
0.356946 x[3]= -0.302131
б) Знайдемо
обернену матрицю .
0-й крок.
А Е
1-й крок.
;
2-й крок.
;
3-й крок.
; ;
.
Даний алгоритм
рішення системи лінійних рівнянь реалізований в програмі Work1_2.
//------------------------------------------------------------
// Work1_2.cpp
//------------------------------------------------------------
// "Числові
методи"
// Завдання 1
// Рішення
системи лінійних рівнянь методом Гауса-Жордана
#include
<stdio.h>
#include
<iostream.h>
#include
<conio.h>
const int nMax=5;
// максимальна кількість рівнянь
const float
ZERO=.0000001;
int
fGausJordan(int n,float A[nMax][nMax],float Ainv[nMax][nMax])
/* Функція
знаходить обернену матрицю
Вхідні дані:
A- масив з
коефіцієнтами при невідомих;
n- порядок
матриці А(кількість рівнянь системи);
Вихідні дані:
Ainv- матриця
обернена до матриці А;
функція повертає
код помилки:
0- помилки немає;
1- матриця А
вироджена. */
{float aMax,t; //
максимальний елемент , тимчасова змінна
int i,j,k,l;
// формуємо
одиничну матрицю
for(i=0; i<n;
i++)
for (j=0; j<n;
j++)
Ainv[i][j] =
(i==j)? 1. : 0.;
for (k=0; k<n;
k++)
{// знаходимо мах
по модулю елемент
aMax=A[k][k];
l=k;
for (i=k+1;
i<n; i++)
if
(fabs(A[i][k])>fabs(aMax))
{ aMax=A[i][k]; l=i;
}
// якщо модуль
головного елементу aMax менший за програмний 0 (ZERO)
if (
fabs(aMax)<ZERO ) return 1;
// якщо потрібно,
міняємо місцями рівняння Pk i Pl
if ( l!=k)
for( j=0; j<n;
j++)
{t=A[l][j]; A[l][j]=A[k][j];
A[k][j]=t;
t=Ainv[l][j];
Ainv[l][j]=Ainv[k][j]; Ainv[k][j]=t;}
// ділимо k-й
рядок на головний елемент
for (j=0; j<n;
j++) { A[k][j]/=aMax; Ainv[k][j]/=aMax; }
// обчислюємо
елементи решти рядків
for (i=0; i<n;
i++)
if( i!=k )
{t=A[i][k];
for (j=0; j<n;
j++)
{A[i][j]-=t*A[k][j];
Ainv[i][j]-=t*Ainv[k][j];}}}
return 0;
} //
fGausJordana()
void fDobMatr(int
n, float A[nMax][nMax], float B[nMax],float X[nMax])
// функція
знаходить добуток матриці А на вектор В і результат повертає в
// векторі Х
{int i,j;
float summa;
for (i=0; i<n;
i++)
{summa=0;
for (j=0; j<n;
j++)
{summa+=A[i][j]*B[j];
X[i]=summa;}}
} // fDobMatr
void main()
{float
A[nMax][nMax],Ainv[nMax][nMax];
float B[nMax];
float X[nMax];
int n,i,j;
char
*strError="\n Error of file !";
FILE
*FileIn,*FileOut;
FileIn=fopen("data_in.txt","r");
// відкриваємо файл для читання
if (FileIn==NULL)
{cout <<
" \"Data_in.txt\": Error open file or file not found
!!!\n";
goto exit;}
FileOut=fopen("data_out.txt","w");
// відкриваємо файл для запису
if
(FileOut==NULL)
{cout <<
" \"Data_out.txt\": Error open file !!!\n";
goto exit;}
if(fscanf(FileIn,"%d",&n)==NULL)
{ cout <<
strError; goto exit;};
for (i=0; i<n;
i++)
for(j=0; j<n;
j++)
fscanf(FileIn,"%f",&(A[i][j]));
for (i=0;
i<n;i++)
if(fscanf(FileIn,"%f",&(B[i]))==NULL)
{ cout <<
strError; goto exit;}
if(fGausJordan(n,A,Ainv)!=0)
{ cout <<
"\n det|A|=0 !"; goto exit;}
fDobMatr(n,Ainv,B,X);
// Вивід
результатів
for (i=0; i<n;
i++)
{printf("
x[%d]= %f ",i+1,X[i]);
fprintf(FileOut,"
x[%d]= %f ",i+1,X[i]);}
fclose(FileIn);
fclose(FileOut);
exit: cout
<< "\n Press any key ...";
getch();}
Результат роботи
програми:
x[1]= 3.017808 x[2]=
0.356946 x[3]= -0.302131
Завдання 2
Задана задача
Коші
,
а) Знайти
розв’язок в табличній формі методом Рунге-Кутта:
, , .
б) Інтерполювати
цю функцію кубічним сплайном. Систему рівнянь для моментів кубічного сплайну
розв’язати методом прогонки. Вибрати крайові умови для кубічного сплайну у вигляді
.
в) Використовуючи
кубічний сплайн з пункту б) обчислити методом Сімпсона
.
Взяти (– кількість відрізків
розбиття).
Рішення.
а) Метод
Рунге-Кутта
Розрахунок будемо
проводити за наступними формулами :
;
;
;
;
;
.
Цей алгоритм
реалізовується в програмі Work2_1.
//------------------------------------------------------------
// Work2_1.cpp
//------------------------------------------------------------
// "Числові
методи"
// Завдання 2
// Рішення задачі
Коші методом Рунге-Кутта
#include
<stdio.h>
#include
<iostream.h>
#include
<conio.h>
typedef float
(*pfunc)(float,float); // pfunc - вказівник на функцію
const int nMax=5;
// максимальна кількість відрізків розбиття
void
fRunge_Kutta(pfunc f, float x0, float y0,float h, int n, float Y[nMax])
/* Функція
знаходить табличне значення функції методом Рунге-Кутта
Вхідні дані:
f - функція
f(x,y)
x0,y0 - початкова
точка;
h - крок;
n- кількість
точок розбиття;
Вихідні дані:
Y- вектор значень
функції*/
{float
k1,k2,k3,k4,x; // максимальний елемент , тимчасова змінна
int i;
x=x0; Y[0]=y0;
for (i=0;
i<n-1; i++)
{k1=f(x,Y[i]);
k2=f(x+h/2,
Y[i]+k1*h/2);
k3=f(x+h/2,
Y[i]+k2*h/2);
k4=f(x+h,
Y[i]+h*k3);
Y[i+1]=Y[i]+(h/6)*(k1+2*k2+2*k3+k4);
x+=h;}}
float
Myfunc(float x,float y)
{return
log10(cos(x+y)*cos(x+y)+2)/log10(5);}
void main()
{float
Y[nMax],h,x0,y0;
int n,i;
char
*strError="\n Error of file !";
FILE
*FileIn,*FileOut, *FileOut2;
FileIn=fopen("data2_in.txt","r");
// відкриваємо файл для читання
if (FileIn==NULL)
{cout <<
" \"Data2_in.txt\": Error open file or file not found !!!\n";
goto exit;}
FileOut=fopen("data2_out.txt","w");
// відкриваємо файл для запису
if
(FileOut==NULL)
{cout <<
" \"Data2_out.txt\": Error open file !!!\n";
goto exit;}
FileOut2=fopen("data2_2in.txt","w");
// відкриваємо файл для запису
if
(FileOut==NULL)
{cout <<
" \"Data2_2in.txt\": Error open file !!!\n";
goto exit;}
if(fscanf(FileIn,"%d%f%f%f,",&n,&h,&x0,&y0)==NULL)
{ cout <<
strError; goto exit;};
fRunge_Kutta(Myfunc,x0,y0,h,n,Y);
// Вивід
результатів
for (i=0; i<n;
i++)
{printf("
x[%d]= %4.2f ",i,Y[i]);
fprintf(FileOut,"
x[%d]= %4.2f ",i,Y[i]);
fprintf(FileOut2,"%4.2f
",Y[i]);}
fclose(FileOut);
exit: cout
<< "\n Press any key ...";
getch();}
Результат роботи
програми (файл "data2_out.txt"):
x[0]= 1.00 x[1]=
1.05 x[2]= 1.10 x[3]= 1.14 x[4]= 1.18
б) В загальному
вигляді кубічний сплайн виглядає наступним чином:
,
Параметри
кубічного сплайну будемо обчислювати , використовуючи формули:
; ;
; , де
– моменти кубічного сплайну.
Моменти мають задовольняти
такій системі рівнянь:
.
Для ; ;
.
Якщо прийняти до
уваги граничні умови , то систему можна записати так
.
В даному випадку
матриця з коефіцієнтів при невідомих є тридіагональною
,
тому для
знаходження моментів кубічних сплайнів застосуємо метод прогонки.
На прямому ході
обчислюємо такі коефіцієнти.
; ;
На зворотньому
ході обчислюємо значення моментів кубічного сплайну.
; .
Для знаходження
коефіцієнті вкубічного сплайну призначена програма Work2_2.
//------------------------------------------------------------
// Work2_2.cpp
//------------------------------------------------------------
// "Числові
методи"
// Завдання 2
// Інтерполювання
функції кубічним сплайном
#include
<stdio.h>
#include
<iostream.h>
#include
<conio.h>
const int nMax=4;
// максимальна кількість відрізків розбиття
const float
x0=0.;// початкова точка сітки
const float
h=0.1;// крок розбиття
// вектори
матриці А
float a[]={0.,
0.5, 0.5};
float b[]={2.,
2., 2.};
float c[]={0.5,
0.5, 0.};
//void
fMetodProgonku( int n,float a[nMax],float b[nMax],float c[nMax],float d[nMax],
float M[nMax+1])
/* Функція знаходить
моменти кубічного сплайну методом прогонки
Вхідні дані:
a,b,c -вектори
матриці А ;
d - вектор
вільних членів;
n- степінь
матриці А;
Вихідні дані:
М- вектор
моментів кубічного сплайну.*/
{float
k[nMax],fi[nMax];
int i;
// прямий хід
for (i=0; i<n;
i++)
{k[i] = (i==0)?
-c[i]/b[i] : -c[i]/(b[i]+a[i]*k[i-1]);
fi[i] = (i==0)?
d[i]/b[i] : (-a[i]*fi[i-1]+d[i])/(b[i]+a[i]*k[i-1]);}
//зворотній хід
for (i=n; i>0;
i--)
M[i] = (i==n)?
fi[i-1] : k[i-1]*M[i+1]+fi[i-1];}
void fSplain( int
n,float h,float Y[nMax+1],float M[nMax+1],float Ak[nMax][4])
/* Функція
обчислює коефіцієнти кубічного сплайну
Вхідні дані:
n- кількість
відрізків розбиття;
H - крок розбиття
відрізку [X0; Xn]]
М- вектор
моментів кубічного сплайну.
Y- вектор значень
функції f(x,y) в точках x[0],x[1],...x[n].
Вихідні дані:
Ak- матриця
коефіцієнтів кубічного сплайну.*/
{int i;
for (i=0; i<n;
i++)
{Ak[i][0] = Y[i];
Ak[i][1] =
(Y[i+1]-Y[i])/h-h/6*(2.*M[i]+M[i+1]);
Ak[i][2] =
M[i]/2;
Ak[i][3] =
(M[i+1]-M[i])/6*h;}}
void main()
{float Y[nMax+1],d[nMax],M[nMax+1],Ak[nMax][4];
int n,i,j;
n=nMax;
M[0]=0; M[n]=0; //крайові
умови
char
*strError="\n Error of file !";
FILE
*FileIn,*FileOut,*FileOut2;
FileIn=fopen("data2_2in.txt","r");
// відкриваємо файл для читання
if (FileIn==NULL)
{ cout <<
" \"Data2_2in.txt\": Error open file or file not found
!!!\n";
goto exit; }
FileOut=fopen("data2_2ou.txt","w");
// відкриваємо файл для запису
if
(FileOut==NULL)
{ cout <<
" \"Data2_2ou.txt\": Error open file !!!\n";
goto exit; }
FileOut2=fopen("data2_3in.txt","w");
// відкриваємо файл для запису
if
(FileOut2==NULL)
{ cout <<
" \"Data2_3in.txt\": Error open file !!!\n";
goto exit; }
// читаємо вектор
Y
for (i=0;
i<=n; i++)
if(fscanf(FileIn,"%f,",&(Y[i]))==NULL)
{ cout <<
strError; goto exit;};
// обчислюємо
вектор d
for (i=1; i<n;
i++) d[i-1]=3/(h*h)*(Y[i+1]-2*Y[i]+Y[i-1]);
//fMetodProgonku(n-1,a,b,c,d,M);
fSplain(
n,h,Y,M,Ak);
// Вивід
результатів в тому числі і для наступного завдання
fprintf(FileOut2,"%d\n",n);
// n - кількість відрізків
// координати
точок сітки по Х
for(float
xi=x0,i=0; i<n; i++) fprintf(FileOut2,"%2.2f ",xi+h*i);
fprintf(FileOut2,"\n");
for (i=0; i<n;
i++)
{for (j=0;
j<4; j++)
{printf("a[%d,%d]=
%4.4f ",i,j,Ak[i][j]);
fprintf(FileOut,"a[%d,%d]=
%4.4f ",i,j,Ak[i][j]);
fprintf(FileOut2,"%4.4f
",Ak[i][j]);}
cout <<
endl;
fprintf(FileOut,"\n");
fprintf(FileOut2,"\n");}
fclose(FileIn);
fclose(FileOut);
exit: cout
<< "\n Press any key ...";
getch();}
Результат роботи
програми (" data2_2uo.txt"):
a[0,0]= 1.0000 a[0,1]=
0.5104 a[0,2]= 0.0000 a[0,3]= -0.0104
a[1,0]= 1.0500 a[1,1]=
0.4793 a[1,2]= -0.3107 a[1,3]= 0.0118
a[2,0]= 1.0960 a[2,1]=
0.4525 a[2,2]= 0.0429 a[2,3]= -0.0068
a[3,0]= 1.1410 a[3,1]=
0.4407 a[3,2]= -0.1607 a[3,3]= 0.0054
в) Розіб’ємо
відрізок на частин.
Складова формула
Сімпсона буде мати вигляд:
;
де - крок розбиття, – значення
функції в точках сітки.
Замінимо значеннями кубічних сплайнів із пункту б) цього
завдання.
Для оцінки
похибки використаємо правило Рунге. Для цього обчислимо наближені значення
інтегралу з кроком (), а потім
з кроком ().
За наближене
значення інтегралу, обчисленого за формулою Сімпсона з поправкою по Рунге приймемо:
.
//------------------------------------------------------------
// Work2_3.cpp
//------------------------------------------------------------
// "Числові
методи"
// Завдання 2
// Обчислення
інтегралу методом Сімпсона з використанням кубічного сплайну
#include
<stdio.h>
#include
<iostream.h>
#include
<conio.h>
#include
<math.h>
// визначення
сплайнового класу
class Tsplain
{public:
int kol; //
кількість рівнянь (відрізків розбиття)
float ** Ak; //
масив коефіцієнтів
float * Xi; //
вектор початків відрізків
float vol(float
x); // функція повертає значення сплайну в точці х
Tsplain(int k);
// constructor};
Tsplain::Tsplain(int
k)
{kol=k;
Xi=new
float[kol];
Ak=new
float*[kol];
for(int i=0;
i<kol; i++) Ak[i]=new float[kol];}
float
Tsplain::vol(float x)
{float s=0.;
int i,t;
// шукаємо
відрізок t де знаходиться точка х
for (i=0;
i<kol; i++) if (x>=Xi[i]) { t=i; break; }
s=Ak[t][0];
for (i=1;
i<kol; i++)
s+=Ak[t][i]*pow((x-Xi[t]),i);
return s;}
float
fSimps(float down,float up, int n, Tsplain *spl)
/* Функція обчислює
інтеграл методом Сімпсона з використанням кубічного сплайну
Вхідні дані:
down,up -границі
інтегрування ;
n- число
відрізків , на яке розбиваєтьться відрізок інтегрування ;
spl - вказівник
на об’єкт класу Tsplain ( кубічний сплайн );
Вихідні дані:
функція повертає
знайдене значення інтегралу.*/
{float s=0;
float
h=(up-down)/(float)n;
int i;
s=spl->vol(down)+spl->vol(up-h);
for (i=2; i<n;
i+=2)
s+=2*(spl->vol(down+i*h));
for (i=1; i<n;
i+=2)
s+=4*(spl->vol(down+i*h));
return s*h;}
void main()
{int kol; //
кількість рівняннь кубічного сплайну
float down,up;
float
I1,I2,I,eps;
int n,i,j;
char
*strError="\n Error of file !";
FILE
*FileIn,*FileOut;
FileIn=fopen("data2_3in.txt","r");
// відкриваємо файл для читання
if (FileIn==NULL)
{ cout <<
" \"Data2_3in.txt\": Error open file or file not found
!!!\n";
goto exit; }
FileOut=fopen("data2_3ou.txt","w");
// відкриваємо файл для запису
if
(FileOut==NULL)
{ cout <<
" \"Data2_3ou.txt\": Error open file !!!\n";
goto exit; }
// читаємо kol
if(fscanf(FileIn,"%d,",&kol)==NULL)
{ cout <<
strError; goto exit;};
Tsplain *sp;
sp=new
Tsplain(kol);
// читаємо вектор
Xi
for(i=0;
i<kol; i++) fscanf(FileIn,"%f,",&(sp->Xi[i]));
// читаємо масив
Ak
for (i=0;
i<kol; i++)
for (j=0;
j<kol; j++) fscanf(FileIn,"%f,",&(sp->Ak[i][j]));
// читаємо n -
кількість відрізків розбиття відрізку інтегрування
if(fscanf(FileIn,"%d,",&n)==NULL)
{ cout <<
strError; goto exit;};
down=sp->Xi[0];
up=sp->Xi[sp->kol-1]+(sp->Xi[sp->kol-1]-sp->Xi[sp->kol-2]);
I1=fSimps(down,up,
n, sp);
I2=fSimps(down,up,
2*n, sp);
eps=(I2-I1)/15;
I=I2+eps;
// Вивід
результатів
printf("I=
%5.5f\n",I);
printf("EPS=
%5.5f\n",eps);
fprintf(FileOut,"I=
%5.5f\n",I);
fprintf(FileOut,"EPS=
%5.5f\n",eps);
fclose(FileIn);
fclose(FileOut);
exit: cout
<< "\n Press any key ...";
getch();}
Результат роботи
програми ("data2_3ou.txt")
I= 1.32213
EPS= 0.00004
Завдання 3
Знайти розв’язок
системи нелінійних рівнянь
,
Рішення.
Умову завдання перепишемо
наступним чином
.
Приймаючи що і то коротко систему
рівнянь можна записати так
.
Якщо відомо деяке
наближення кореня системи рівнянь,
то поправку можна знайти рішаючи систему
.
Розкладемо ліву
частину рівняння по степеням малого вектору , обмежуючись
лінійними членами
.
== –
матриця похідних (матриця Якобі) ().
Складемо матрицю
похідних (матрицю Якобі):
Якщо , то ,
де – матриця обернена до матриці Якобі.
Таким чином
послідовне наближення кореня можна обчислити за формулою
або
.
Умовою закінчення
ітераційного процесу наближення корення вибираємо умову
,
– евклідова відстань між двома послідовними
наближеннями ;– число, що задає мінімальне
наближення.
Для рішення
систем нелінійних рівнянь за даним алгоритмом призначена програма
Work3.cpp
//------------------------------------------------------------
// Work3.cpp
//------------------------------------------------------------
// "Числові
методи"
// Завдання 3
// Розв’язування
системи нелінійних рівнянь методом Ньютона
#include
<stdio.h>
#include
<iostream.h>
#include
<conio.h>
#include
<math.h>
#include
"matrix.h"
const int N=2; //
степінь матриці Якобі (кількість рівнянь)
typedef void
(*funcJ) (float[N], float[N][N]);
void
fJakobi(float X[N],float J[N][N])
// функції , які
складають матрицю Гессе
{J[0][0]=cos(X[0]);
J[0][1]=cos(X[1]);
J[1][0]=2*X[0]; J[1][1]=-2*X[1]+1;}
typedef void
(*funcF) (float[N], float[N]);
void fSist(float
X[N],float Y[N])
{Y[0]=sin(X[0])+sin(X[1])-1;
Y[1]=X[0]*X[0]-X[1]*X[1]+X[1];}
//int
NelinSist(float X[N], funcJ pJakobi, funcF pSist,float eps)
/* Функція
знаходить кореня системи нелінійних рівнянь методом Ньютона.
Вхідні дані:
X[N] - вектор
значень початкового наближення
pSist - вказівник
на функцію, яка обчислює по
заданим значенням
X[] значення функції f(X) ;
pJakobi -
вказівник на функцію, яка обчислює по
заданим значенням
X[] елементи матриці W ;
Вихідні дані:
X[N] - вектор
наближеного значення мінімуму.
Функція повертає
код помилки
0 - система
рівнянь успішно розв’язана
1 - det W=0 */
{int n=N;
float len;
float
W[N][N],Winv[N][N],Y[N],deltaX[N];
do
{pJakobi(X,W);
if(invMatr(n,W,Winv))
return 1;
pSist(X,Y);
DobMatr(n,Winv,Y,deltaX);
X[0]-=deltaX[0];
X[1]-=deltaX[1];
len=sqrt(deltaX[0]*deltaX[0]+deltaX[1]*deltaX[1]);}
while
(len>eps);
return 0;}
//int main()
{float X[N],eps;
// початкові
умови
eps=.0001;
X[0]=0.0;
X[1]=1.0;
if
(NelinSist(X,fJakobi,fSist,eps))
{ cout <<
"Error of matrix: detW=0"; return 1;}
printf("X= %5.4f
Y= %5.4f\n",X[0],X[1]);
cout <<
"\n Press any key ...";
getch();}
Результат роботи
програми:
X= 0.1477 Y=
1.0214
Завдання 4
Знайти точку мінімуму
та мінімальне значення функції
,
методом Ньютона.
Рішення.
;
Матриця Гессе
.
Ітераційний
процес послідовного наближення мінімуму функції буде таким:
,
де – матриця обернена до матриці Гессе.
Для закінчення
ітераційного процесу використаємо умову
або
.
Для пошуку мінімуму
функції за методом Ньютона призначена програма Work4.cpp
//------------------------------------------------------------
// matrix.h
//-----------------------------------------------------------
const int nMax=2;
// кількість рівнянь
const float
ZERO=.00000001;
int invMatr(int
n,float A[nMax][nMax],float Ainv[nMax][nMax])
/* Функція
знаходить обернену матрицю
Вхідні дані:
A- масив з
коефіцієнтами при невідомих;
n- порядок
матриці А(кількість рівнянь системи);
Вихідні дані:
Ainv- матриця
обернена до матриці А;
функція повертає
код помилки:
0- помилки немає;
1- матриця А
вироджена. */
{float aMax,t; //
максимальний елемент , тимчасова змінна
int i,j,k,l;
// формуємо
одиничну матрицю
for(i=0; i<n;
i++)
for (j=0; j<n;
j++)
Ainv[i][j] =
(i==j)? 1. : 0.;
for (k=0; k<n;
k++)
{// знаходимо мах
по модулю елемент
aMax=A[k][k];
l=k;
for (i=k+1;
i<n; i++)
if
(fabs(A[i][k])>fabs(aMax))
{ aMax=A[i][k]; l=i;
}
if (
fabs(aMax)<ZERO ) return 1;
// якщо потрібно,
міняємо місцями рівняння Pk i Pl
if ( l!=k)
for( j=0; j<n;
j++)
{t=A[l][j]; A[l][j]=A[k][j];
A[k][j]=t;
t=Ainv[l][j];
Ainv[l][j]=Ainv[k][j]; Ainv[k][j]=t;}
// ділимо k-й
рядок на головний елемент
for (j=0; j<n;
j++) { A[k][j]/=aMax; Ainv[k][j]/=aMax; }
// обчислюємо
елементи решти рядків
for (i=0; i<n;
i++)
if( i!=k )
{t=A[i][k];
for (j=0; j<n;
j++)
{A[i][j]-=t*A[k][j];
Ainv[i][j]-=t*Ainv[k][j];}}}
return 0;}
void DobMatr(int
n, float A[nMax][nMax], float B[nMax],float X[nMax])
// функція
знаходить добуток матриці А на вектор В і результат повертає в
// векторі Х
{int i,j;
float summa;
for (i=0; i<n;
i++)
{summa=0;
for (j=0; j<n;
j++)
{summa+=A[i][j]*B[j];
X[i]=summa;}}
} // DobMatr
//------------------------------------------------------------
// Work4.cpp
//------------------------------------------------------------
// "Числові
методи"
// Завдання 4
// Пошук мінімуму
функції методом Ньютона
#include
<stdio.h>
#include
<iostream.h>
#include
<conio.h>
#include
<math.h>
#include
"matrix.h"
const int N=2; //
степінь матриці Гессе
float
myFunc(float x[N])
{ return
exp(-x[1])-pow(x[1]+x[0]*x[0],2); }
typedef void
(*funcH) (float[N], float[N][N]);
void fHesse(float
X[N],float H[N][N])
// функції , які
складають матрицю Гессе
{H[0][0]=-4.*X[1]-6.*X[0]*X[0];
H[0][1]=-4.*X[0];
H[1][0]=-4; H[1][1]=exp(-X[1])-21;}
typedef void
(*funcG) (float[N], float[N]);
void fGrad(float
X[N],float Y[N])
{Y[0]=-4*X[1]*X[0]-3*X[0]*X[0]*X[0];
Y[1]=exp(-X[1])-2.*X[1]-2*X[0]*X[0];}
//int fMin(float
X[N], funcG pGrad, funcH pHesse,float eps)
/* Функція
знаходить точку мінімуму рівняння методом Ньютона.
Вхідні дані:
X[N] - вектор
значень початкового наближення
pGrad - вказівник
на функцію, яка обчислює по
заданим значенням
X[] значення grad f(X) ;
pHesse -
вказівник на функцію, яка обчислює по
заданим значенням
X[] елементи матриці H ;
Вихідні дані:
X[N] - вектор
наближеного значення мінімуму.
Функція повертає
код помилки
0 - система
рівнянь успішно розв’язана
1 - det H=0 */
{int n=N;
float modGrad;
float
Hesse[N][N],HesseInv[N][N],Grad[N],deltaX[N];
do
{pHesse(X,Hesse);
if(invMatr(n,Hesse,HesseInv))
return 1;
pGrad(X,Grad);
DobMatr(n,HesseInv,Grad,deltaX);
X[0]-=deltaX[0];
X[1]-=deltaX[1];
modGrad=sqrt(deltaX[0]*deltaX[0]+deltaX[1]*deltaX[1]);}
while
(modGrad>eps);
return 0;}
//int main()
{float X[N],eps;
// початкові
умови
eps=.0001;
X[0]=0.5;
X[1]=0.5;
if
(fMin(X,fGrad,fHesse,eps))
{ cout <<
"Error of matrix: detH=0"; return 1;}
printf("X=
%5.5f Y= %5.4f\n f(x,y)= %4.3f\n ",X[0],X[1],myFunc(X));
cout <<
"\n Press any key ...";
getch();}
Результат роботи
програми:
x= -0.0000 y=
0.3523
f(x,y)= 0.579
Завдання 5
Розкласти в ряд
Фурьє функцію на відрізку [-1; 1].
Рішення.
В загальному
вигляді ряд Фурьє функції виглядає так:
, де =0,
1, 2, …
В нашому випадку
відрізок розкладення функції – [-1; 1], тому проводимо лінійну заміну змінної : . Тоді умова завдання
стане такою:
Для наближеного
обчислення коефіцієнтів ряду Фурьє використаємо квадратурні формули, які утворюються
при інтерполяції алгебраїчним многочленом підінтегральних функцій
і :
(1)
(2)
(3)
де – число вузлів квадратурної формули;
– вузли квадратурної формули , =0, 1, 2, …, 2
Для обчислення
наближених значень коефіцієнтів ряду Фурьє по формулам (1), (2), (3) призначена
процедура (функція) Fourier.
//---------------------------------------------------------
// Work5.h
//---------------------------------------------------------
#include
<math.h>
const double
Pi=3.141592653;
// функція
повертає і-й вузол квадратурної формули, 2N+1-кілікість вузлів
inline double
FuncXi(int N, int i) {return -Pi+(2*Pi*i)/(2*N+1);}
typedef double
(*Func)(double); // опис типу вказівника на функцію
char Fourier(Func
F_name, int CountN, int CountK,double **Arr)
/* функція
обчислює коефіцієнти ряду Фурьє
Вхідні дані:
F_mame -
вказівник на функцію(функтор), яка обчислює значення функції
f(x) на відрізку
[-п; п];
CountN - число,
яке задає розбиття відрізка [-п; п] на рівні частини
довжиною
2п/(2*CountN+1);
CountK -
кількість обчислюваних пар коефіцієнтів;
Вихідні дані:
Arr - двомірний
масив розміру [CountK+1][2], в якому
знаходяться
обчислені коефіцієнти ряду Фурьє.
Функція повертає
значення коду помилки:
Fourier=0 -
помилки немає;
Fourier=1 - якщо
CountN<CountK;
Fourier=2 - якщо
CountK<0;*/
{double
a,b,sumA,sumB;
int i,k;
if (CountN <
CountK) return 1;
if (CountK <
0) return 2;
// обчислення а0
sumA=0;
for (i=0; i<
2*CountN+1; i++) sumA+=F_name(FuncXi(CountN,i));
a=1./(2*CountN+1)*sumA;
Arr[0][0]=a;
// обчислення
коефіцієнтів аk,bk
for (k=1;
k<=CountK; k++)
{sumA=sumB=0;
for (i=0;
i<2*CountN+1; i++)
{sumA+=F_name(FuncXi(CountN,i))*cos(2*Pi*k*i/(2*CountN+1));
sumB+=F_name(FuncXi(CountN,i))*sin(2*Pi*k*i/(2*CountN+1));}
a=(2./(2*CountN+1))*sumA;
b=(2./(2*CountN+1))*sumB;
Arr[k][0]=a;
Arr[k][1]=b;}
return 0;}
//------------------------------------------------------------
// Work5.cpp
//------------------------------------------------------------
// "Числовы
методи"
// Завдання 5
// Розрахунок
коэфіцієнтів ряду Фурьє
#include
"Work5.h"
#include
<stdio.h>
#include
<iostream.h>
#include
<conio.h>
double f(double
x)
// функція
повертає значення функції f(x)
{return
sqrt(Pi*Pi*x*x+1);}
const int N=20;
// константа, яка визначає розбиття відрізка [-п; п]
// на рівні
частини
const int
CountF=15; // кількість пар коефіцієнтів ряду
void main()
{double **data;
data = new double
*[CountF+1];
for ( int i=0;
i<=CountF; i++) data[i] = new double [2];
if
(Fourier(f,N,CountF,data) != 0)
{cout <<
"\n Помилка !!!";
return;}
// Вивід
результатів
printf("a0=
%lf\n",data[0][0]);
for (int
i=1;i<=CountF;i++)
printf("a%d
= %lf , b%d = %lf\n",i,data[i][0],i,data[i][1]);
cout <<
" Press any key ...";
getch();}
Результат роботи
програми Work5.cpp