Содержание:
-
Цель работы…………………………………………………………………………………..2
-
Исходные данные……………………………………………………………………………2
-
Графическое решение……………………………………………………………………….2
-
Метод Ньютона………………………………………………………………………………2
-
Листинг программы (Метод Ньютона)………………………………………………..2
-
Результат программы (Метод Ньютона)………………………………………………3
-
-
Метод простой итерации……………………………………………………………………3
-
Метод Гаусса-Зейделя………………………………………………………………………6
-
Листинг программы (Методы простой итерации и Гаусса-Зейделя)………………..8
-
Результат программы (Методы простой итерации и Гаусса-Зейделя)………………9
-
-
Вывод…………………………………………………………………………………………9
-
Цель работы: С помощью знаний полученных на лекциях решить СНАУ в структуре MS 2008(C++) методом Ньютона, методом простой итерации и методом Гаусса-Зейделя.
-
Исходные данные:
-
-
-
Графическое решение
A(1,23;0,56), B(0,24;-0,98), C(-1,23;-0,56), B(-0,24;0,98). За начальное приближение берём точку (1,2;0,5) с соответствующими координатами.
-
-
-
-
Метод Ньютона
-
Листинг программы (метод Ньютона):
-
#include <stdafx.h>
#include <iostream>
#include <math.h>
#include <conio.h>
#include <locale>
using namespace std;
double F(double x, double y)
{
return tan(x*y+0.3)-x*x;
}
double G(double x, double y)
{
return 0.9*x*x + 2*y*y - 2;
}
double dFdX(double x, double y)
{
return y/pow(cos(x*y+0.3), 2)-2*x;
}
double dFdY(double x, double y)
{
return x/pow(cos(x*y+0.3), 2);
}
double dGdX(double x, double y)
{
return 1.8*x;
}
double dGdY(double x, double y)
{
return 4*y;
}
int _tmain(int argc, _TCHAR* argv[])
{
double x_new, x_old, y_new, y_old;
double e = 0.01;
x_new = 1.2;
y_new = 0.5;
do
{
x_old = x_new;
y_old = y_new;
x_new = x_old + (dFdY(x_old, y_old)*F(x_old, y_old) - dGdY(x_old, y_old)*G(x_old, y_old)) / (dGdY(x_old, y_old)*dFdX(x_old, y_old) - dFdY(x_old, y_old)*dGdX(x_old, y_old));
y_new = y_old + (dGdX(x_old, y_old)*F(x_old, y_old) - dFdX(x_old, y_old)*G(x_old, y_old)) / (dGdY(x_old, y_old)*dFdX(x_old, y_old) - dFdY(x_old, y_old)*dGdX(x_old, y_old));
}
while((abs(x_new - x_old) >= e) && (abs(x_new - x_old) >= e));
cout<<"x = "<<x_new<<endl;
cout<<"y = "<<y_new<<endl;
getch();
}
-
-
-
-
-
-
Результат программы (метода Ньютона)
-
-
Метод простой итерации
Напомним, что нам требуется решить систему линейных уравнений, которая в матричном виде записывается как:
,
где , , .
Предположим, что диагональные элементы матриц A исходной системы не равны 0 (aii ≠ 0, i = 1, 2, …, n). Разрешим первое уравнение системы относительно x1, второе относительно x2 и т.д. Получим следующую эквивалентную систему, записанную в скалярном виде:
(1),
Теперь, задав нулевое приближение , по рекуррентным соотношениям (1) можем выполнять итерационный процесс, а именно:
(2)
Аналогично находятся следующие приближения , где в (2) вместо необходимо подставить .
Или в общем случае:
. (3)
или
Условие окончания итерационного процесса .
Достаточное условие сходимости: Если выполнено условие диагонального преобладания, т.е. , то итерационный процесс (3) сходится при любом выборе начального приближения. Если исходная система уравнений не удовлетворяет условию сходимости, то ее приводят к виду с диагональным преобладанием.
Выбор начального приближения влияет на количество итераций, необходимых для получения приближенного решения. Наиболее часто в качестве начального приближения берут или .
Замечание. Указанное выше условие сходимости является достаточным, т.е. если оно выполняется, то процесс сходится. Однако процесс может сходиться и при отсутствии диагонального преобладания, а может и не сойтись.
Пример.
Решить систему линейных уравнений с точностью :
|
8 |
4 |
2 |
|
10 |
|
x1 |
|
= |
3 |
5 |
1 |
= |
5 |
= |
x2 |
|
|
3 |
–2 |
10 |
|
4 |
|
x3 |
|
Решение прямыми методами, например, обратной матрицей, даёт решение:
.
Найдем решение методом простой итерации. Проверяем условие диагонального преобладания: , , .
Приводим систему уравнений к виду (1):
.
Начальное приближение . Дальнейшие вычисления оформим в виде таблицы:
k |
x1 |
x2 |
x3 |
точность |
0 |
0 |
0 |
0 |
|
1 |
1.250 |
1.000 |
0.400 |
1.2500 |
2 |
0.650 |
0.170 |
0.225 |
0.8300 |
3 |
1.109 |
0.565 |
0.239 |
0.4588 |
|
……… |
|
|
|
4 |
0.908 |
0.287 |
0.180 |
0.2781 |
5 |
1.061 |
0.419 |
0.185 |
0.1537 |
6 |
0.994 |
0.326 |
0.165 |
0.0931 |
7 |
1.046 |
0.370 |
0.167 |
0.0515 |
8 |
1.023 |
0.594 |
0.160 |
0.2235 |
9 |
0.913 |
0.582 |
0.212 |
0.1101 |
10 |
0.906 |
0.505 |
0.242 |
0.0764 |
11 |
0.937 |
0.495 |
0.229 |
0.0305 |
12 |
0.945 |
0.516 |
0.218 |
0.0210 |
|
…… |
|
|
|
13 |
0.937 |
0.523 |
0.220 |
0.0077 |
Здесь
,
-
-
-
-
-
-
Метод Зейделя (Гаусса-Зейделя)
Расчетные формулы имеют вид:
т.е. для подсчета i–й компоненты (k+1)–го приближения к искомому вектору используется уже вычисленное на этом, т.е. (k+1)–м шаге, новые значения первых i–1 компонент.
Подробные формулы имеют вид:
Достаточное условие сходимости этого метода такое же, как и для метода простой итерации, т.е. диагональное преобладание:
Начальное приближение:
Найдем решение примера системы уравнений методом Гаусса – Зейделя.
Расчетные формулы:
k |
x1 |
x2 |
x3 |
точность |
0 |
0 |
0 |
0 |
|
1 |
1.250 |
0.250 |
0.075 |
1.2500 |
2 |
1.106 |
0.321 |
0.132 |
0.1438 |
3 |
1.056 |
0.340 |
0.151 |
0.0500 |
4 |
1.042 |
0.344 |
0.156 |
0.0139 |
5 |
1.039 |
0.346 |
0.157 |
0.0036 |
Так как, что метод Гаусса-Зейделя является модифицированным методом простых итераций, реализуем оба метода в одной программе.
Точность eps = 0.0001
-
Листинг программы (Методы простой итерации и Гаусса-Зейделя):
#include <stdafx.h>
#include <math.h>
#include <iostream>
#include <conio.h>
#include <locale>
using namespace std;
double funcx(double, double);
double funcy(double, double);
int _tmain(int argc, _TCHAR* argv[])
{
setlocale(LC_ALL,"Russian");
cout<<"Метод простых итераций\n"<<endl;
int k = 0;
double x, y, newx, tx, ty, newy, eps;
x=1.23;
y=0.55;
eps=0.0001;
do
{
k++;
tx = x;
ty = y;
newx = funcx(x, y);
newy = funcy(x, y);
x = newx;
y = newy;
cout<<"Итерация #"<<k<<endl<<"x = "<<x<<", y = "<<y<<endl;
}
while(fabs(x - tx) > eps || fabs(y - ty) > eps);
cout<<"Ответ:"<<endl<<"x = "<<newx<<", y = "<<newy<<endl;
cout<<"\n"<<endl;
cout<<"Метод Гаусса-Зейделя"<<endl;
k=0;
x=1.23;
y=0.55;
eps = 0.0001;
do
{
k++;
tx = x;
ty = y;
newx = funcx(x, y);
x = newx;
newy = funcy(x, y);
y = newy;
cout<<"Итерация #"<<k<<endl<<"x = "<<x<<", y = "<<y<<endl;
}
while(fabs(x - tx) > eps && fabs(y - ty) > eps);
cout<<"Ответ:"<<endl<<"x = "<<newx<<", y = "<<newy<<endl;
getch();
}
double funcx(double x, double y)
{
return (atan(x*x)-0.3)/y;
}
double funcy(double x, double y)
{
return sqrt(fabs(1-0.45*x*x));
}
-
-
-
-
-
-
-
-
Результат программы (метод Гаусса-Зейделя):
-
-
Вывод:
Метод Зейделя работает быстрее, чем метод простых итераций.