Метод Зейделя на C++

3 комментария

Для написания программы, решающей систему линейных уравнения методом итерации или Зейделя, Вам потребуется среда разработки, например Visual Studio 2008 или Dev-C++.

Создадим новый проект пустой проект и добавим в него файл исходного кода — main.cpp со следующим содержимым

Листинг 1.1 — main.cpp

#include <iostream>
#include <cmath>
#include "norm.h"
#include "iterat.h"
using namespace std;

int main()
{
    setlocale(LC_ALL, "");
    double eps, A[10][10], B[10];
    int N, i, j;
    int method;
    cout << "Введите размер квадратной матрицы: ";
    cin >> N;
    cout << "Введите точность вычислений: ";
    cin >> eps;
    cout << "Заполните матрицу А: " << endl << endl;
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) {
            cout << "A[" << i << "][" << j << "] = ";
            cin >> A[i][j];
        }
    }
    cout << "\nВаша матрица А:" << endl;
    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++) {
            cout << A[i][j] << " ";
        }
        cout << endl;
    }
    cout << "\nЗаполните столбец свободных членов: " << endl;
    for (i = 0; i < N; i++) {
        cout << "В[" << i+1 << "] = ";
        cin >> B [i];
    }
    cout << "\nВыберите метод решения системы (1 - Гаусс / 2 - Зейдель): "; 
    cin >> method;
    cout << endl;
    iterat(A,B,N,eps,method);
    return 0;
}

Теперь создадим заголовочный файл norm.h, содержащий прототипы функций, вычисляющих нормы матрицы, и iterat.h, содержащий прототип функции iterat(), которая считает количество итераций.

Листинг 1.2 — norm.h

double firstNorm(double [10][10], int n, int m);
double secondNorm(double [10][10], int n, int m);
double thirdNorm(double [10][10], int n, int m);

Листинг 1.3 — iterat.h

double iterat(double A[10][10], double B[10], int N, double eps, int method);

Теперь добавим в проект третий заголовочный файл okr.h — в нем будет находиться прототип функции округления

Листинг 1.4 — okr.h

double okr(double X, double eps);

Создадим еще три файла — norm.cpp, iterat.cpp и okr.cpp

Листинг 1.5 — norm.cpp

#include <cmath>

double firstNorm(double  A[10][10],  int n, int m)
{
    int i, j;
    double sum = 0, subSum;
    for (i = 0; i < n; i++) {
        subSum = 0;
        for (j = 0; j < m; j++) {
            subSum += abs(A[i][j]);
        }
        if(subSum > sum) {
            sum = subSum;
        }
    }
    return sum;
}

double secondNorm(double  A[10][10], int n, int m)
{
    int i, j;
    double sum = 0, subSum;
    for (j = 0; j < n; j++) {
        subSum = 0;
        for (i = 0; i < m; i++) {
            subSum += abs(A[i][j]);
        }
        if(subSum > sum) {
            sum = subSum;
        }
    }
    return sum;
}

double thirdNorm(double A[10][10], int n, int m)
{
    int i, j;
    double sum = 0;
    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            sum += (A[i][j] * A[i][j]);
        }
    }
    sum = sqrt(sum);
    return sum;
}

В файле iterat.cpp будет описана функция, вычисляющая количество итераций по по методу Зейделя, либо по методу простых итераций.

Листинг 1.6 — iterat.cpp

#include <iostream>
#include <cmath>
#include "norm.h"
#include "okr.h"

using namespace std;

double iterat(double A[10][10], double B[10], int N, double eps, int method)
{
    if (thirdNorm(A, N, N) < 1) {
        int k = 0;
        int i, j;
        double X[10];
        double Y[10];
        double s;
        double g;

        for(i = 0; i < N; i++) {
            X[i] = B[i];
        }
        do {
            s = 0; k++;
            if (method != 1 && method != 2) {
                while (method != 1 && method != 2) {
                    cerr << "Неверное значение!" << endl;
                    cout << "\nВыберите метод решения системы (1 - Гаусс / 2 - Зейдель): ";
                    cin >> method;
                    cout << endl;
                }
            }
            if (method == 1) { // Решаем систему методом Гаусса.
                for (i = 0; i < N; i++) {
                    Y[i] = B[i];
                    for (j = 0; j < N; j++) {
                        Y[i] = Y[i] + A[i][j] * X[j];
                    }
                    s += (X[i] - Y[i]) * (X[i] - Y[i]);
                }
                for (i = 0; i < N; i++) {
                    X[i] = Y[i];
                }
            } else if (method == 2) { // Решаем систему методом Зейделя.
                for (i = 0; i < N; i++) {
                    g = B[i];
                    for (j = 0; j < N; j++) {
                        g = g + A[i][j] * X[j];
                    }
                    s += (X[i] - g) * (X[i] - g);
                    X[i] = g;
                }
             }
        } while (sqrt(s) >= eps * (1 - thirdNorm(A, N, N)) / thirdNorm(A, N, N));

        if (method == 1 || method == 2) {
            cout << "Решение системы:" << endl;
            for (i = 0; i < N; i++) {
                cout << "X" << i << " = " << okr(X[i],eps) << endl;
            }
            cout << "Число итераций: " << k-1 << endl;
            cout << "Первая норма матрицы A: " << firstNorm(A,N,N) << endl;
            cout << "Вторая норма матрицы A: " << secondNorm(A,N,N) << endl;
            cout << "Третья норма матрицы A: " << thirdNorm(A,N,N) << endl;
        }

    } else {
        cerr << "Условие сходимости по евклидовой метрике не выполняется!" << endl;
    }

    return 0;
}

И последний файл — okr.cpp, содержащий определение функции округления

Листинг 1.7 — okr.cpp

#include <cmath>

using namespace std;

double okr(double X, double eps)
{
    int i = 0;
    while (eps != 1) {
        i++;
        eps *= 10;
    }
    int okr = pow(double(10), i);
    X = int(X * okr + 0.5) / double(okr);
    return X;
}

Вы можете скачать полный архив со всем файлами проекта.

После регистрации реклама на сайте отображаться не будет.
Обсудите статью на форуме.

Комментарии к статье: 3

Подождите, загружаются комментарии...

Оставить комментарий

Если не хотите больше вводить капчу — создайте аккаунт.

Предпросмотр комментария

Ваш комментарий пуст.