Добавил:
tg: @petmanchenko Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

ПР №3 Разработка алгоритмов и программ, решающих линейные уравнения

.doc
Скачиваний:
1
Добавлен:
02.02.2025
Размер:
233.47 Кб
Скачать

ФЕДЕРАЛЬНОЕ АГЕНТСТВО СВЯЗИ

ФЕДЕРАЛЬНОЕ ГОСУДАРСТВЕННОЕ БЮДЖЕТНОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ ВЫСШЕГО ОБРАЗОВАНИЯ

«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ТЕЛЕКОММУНИКАЦИЙ ИМ. ПРОФ. М.А. БОНЧ-БРУЕВИЧА»

(СПбГУТ)

Кафедра безопасности информационных систем

ОТЧЁТ

по итоговой работе №3 на тему: «Разработка алгоритмов и программ, решающих линейные уравнения»

по дисциплине «Алгоритмы и структуры данных»

Выполнил: студент группы ИСТ-931, Гетманченко П.А.

«13» октября 2020 г. ___________/П.А. Гетманченко /

Принял: к.ф.-м.н., доцент, Моисеев И. А.

«13» октября 2020 г. __________/ И. А. Моисеев /

Основная часть

Цель работы: разработать пользовательский алгоритм и программу для решения линейных уравнений двумя разными методами, такими как: метод Крамера и метод Гаусса. Приобрести навыки и умения анализа алгоритма.

Результаты выполнения работы

Задание 1:

Решить линейное уравнение через определители (метод Крамера).

Пример из книги:

#include <iostream>

#include <iomanip>

#include <Windows.h>

using namespace std;

// вычисление определителя матрицы

double Determ(double** A, int size, int &opCount1, int& opCount2)

{

double** matr = nullptr;

double det = 0;

int i, j;

switch (size)

{

case 1:

det = A[0][0];

break;

case 2:

det = A[0][0] * A[1][1] - A[0][1] * A[1][0];

// 2 умножения и одно вычитание

opCount1 += 2;

opCount2++;

break;

default:

matr = new double*[size - 1];

for (i = 0; i < size; ++i)

{

for (j = 0; j < size - 1; ++j)

{

if (j < i)

matr[j] = A[j];

else

matr[j] = A[j + 1];

}

det += pow((double)-1, (i + j)) * Determ(matr, size - 1, opCount1, opCount2) * A[i][size - 1];

// если считать число операций как по формуле

// здесь есть 2 операции:

// 1) умножение определителя минора на элемент матрицы

// 2) прибавляем (или вычистаем) получившееся значение к текущему значению определителя

opCount1++;

opCount2++;

}

delete[] matr;

break;

}

return det;

}

// решение СЛАУ через определитель (метод Крамера)

void Kramer(double** A, double* x, int size)

{

int opCount1 = 0; // счётчик операций (умножение и деление)

int opCount2 = 0; // счётчик операций (сложение и вычитание)

// вычисляем определитель матрицы системы

double det = Determ(A, size, opCount1, opCount2);

// выделяем память под матрицу

// для вычисления дополнительных определителей

double** B = new double*[size];

for (int i = 0; i < size; i++)

B[i] = new double[size];

for (int k = 0; k < size; k++)

{

// заполняем матрицу B

for (int i = 0; i < size; i++)

{

for (int j = 0; j < size; j++)

{

if (j == k)

B[i][j] = A[i][size];

else

B[i][j] = A[i][j];

}

}

// вычисляем значение k-го корня

x[k] = Determ(B, size, opCount1, opCount2) / det;

opCount1++; // ещё одна операция деления

}

// освобождаем память

for (int i = 0; i < size; i++)

delete[] B[i];

delete[] B;

cout << "Вычисление через определитель (метод Крамера) завершено" << endl

<< "выполнено " << opCount1 + opCount2 << " арифметических операций, их них:" << endl;

cout << "операций умножения и деления - " << opCount1 << endl;

cout << "операций сложения и вычитания - " << opCount2 << endl;

}

int main()

{

setlocale(LC_ALL, "Russian");

// матрица СЛАУ

double src[][5] = {

{ 2, 1, -5, 1, 8},

{ 1, -3, 0, -6, 9},

{ 0, 2, -1, 2, -5},

{ 1, 4, -7, 6, 0}

};

// создаём и заполняем динамический массив указателей на строки

// для работы с матрицей системы

const int size = sizeof(src) / sizeof(src[0]);

double** rows = new double*[size];

for (size_t i = 0; i < size; i++)

rows[i] = src[i];

//int size = 0;

//cout << "Введите размерность СЛАУ: ";

//cin >> size;

//// выделяем память под матрицу системы

//double ** rows = new double* [size];

//for (int i = 0; i < size; i++)

// rows[i] = new double[size + 1];

//cout << "Введите построчно элементы матрицы СЛАУ" << endl;

//for (int i = 0; i < size; i++)

//{

// for (int j = 0; j <= size; j++)

// {

// //cout << "A[" << i + 1 << "][" << j + 1 << "] = ";

// cin >> rows[i][j];

// }

//}

cout << "Система заполнена" << endl;

for (int i = 0; i < size; i++)

{

for (int j = 0; j <= size; j++)

cout << setw(4) << rows[i][j];

cout << endl;

}

cout << endl;

// массив для корней системы

double *x = new double[size];

// переменные для вычисления времени выполнения

__int64 timerFreq, counterAtStart, counterAtStop;

double duration;

// засекаем время начала вычислений

QueryPerformanceFrequency((LARGE_INTEGER*)&timerFreq);

QueryPerformanceCounter((LARGE_INTEGER*)&counterAtStart);

// решаем систему методом Крамера (определителей)

Kramer(rows, x, size);

QueryPerformanceCounter((LARGE_INTEGER*)&counterAtStop);

duration = (double)(counterAtStop - counterAtStart) / timerFreq;

cout << "Время выполнения: " << duration << " мс" << endl;

// выводим резулльтат на экран

cout << endl << "Решение СЛАУ" << endl;

for (int i = 0; i < size; i++)

cout << "x[" << i + 1 << "] = " << x[i] << endl;

// освобождаем память

//for (size_t i = 0; i < size; i++)

// delete[] rows[i];

delete[] rows;

delete[] x;

system("Pause");

return 0;

}

Результат:

Сама программа решения линейного уравнения через определители (метод Крамера):

#include <iostream>

#include <iomanip>

#include <Windows.h>

using namespace std;

// вычисление определителя матрицы

double Determ(double** A, int size, int &opCount1, int& opCount2)

{

double** matr = nullptr;

double det = 0;

int i, j;

switch (size)

{

case 1:

det = A[0][0];

break;

case 2:

det = A[0][0] * A[1][1] - A[0][1] * A[1][0];

// 2 умножения и одно вычитание

opCount1 += 2;

opCount2++;

break;

default:

matr = new double*[size - 1];

for (i = 0; i < size; ++i)

{

for (j = 0; j < size - 1; ++j)

{

if (j < i)

matr[j] = A[j];

else

matr[j] = A[j + 1];

}

det += pow((double)-1, (i + j)) * Determ(matr, size - 1, opCount1, opCount2) * A[i][size - 1];

// если считать число операций как по формуле

// здесь есть 2 операции:

// 1) умножение определителя минора на элемент матрицы

// 2) прибавляем (или вычистаем) получившееся значение к текущему значению определителя

opCount1++;

opCount2++;

}

delete[] matr;

break;

}

return det;

}

// решение СЛАУ через определитель (метод Крамера)

void Kramer(double** A, double* x, int size)

{

int opCount1 = 0; // счётчик операций (умножение и деление)

int opCount2 = 0; // счётчик операций (сложение и вычитание)

// вычисляем определитель матрицы системы

double det = Determ(A, size, opCount1, opCount2);

// выделяем память под матрицу

// для вычисления дополнительных определителей

double** B = new double*[size];

for (int i = 0; i < size; i++)

B[i] = new double[size];

for (int k = 0; k < size; k++)

{

// заполняем матрицу B

for (int i = 0; i < size; i++)

{

for (int j = 0; j < size; j++)

{

if (j == k)

B[i][j] = A[i][size];

else

B[i][j] = A[i][j];

}

}

// вычисляем значение k-го корня

x[k] = Determ(B, size, opCount1, opCount2) / det;

opCount1++; // ещё одна операция деления

}

// освобождаем память

for (int i = 0; i < size; i++)

delete[] B[i];

delete[] B;

cout << "Вычисление через определитель (метод Крамера) завершено" << endl

<< "выполнено " << opCount1 + opCount2 << " арифметических операций, их них:" << endl;

cout << "операций умножения и деления - " << opCount1 << endl;

cout << "операций сложения и вычитания - " << opCount2 << endl;

}

int main()

{

setlocale(LC_ALL, "Russian");

//// матрица СЛАУ

//double src[][5] = {

// { 2, 1, -5, 1, 8},

// { 1, -3, 0, -6, 9},

// { 0, 2, -1, 2, -5},

// { 1, 4, -7, 6, 0}

//};

//// создаём и заполняем динамический массив указателей на строки

//// для работы с матрицей системы

//const int size = sizeof(src) / sizeof(src[0]);

//double** rows = new double* [size];

//for (size_t i = 0; i < size; i++)

// rows[i] = src[i];

int size = 0;

cout << "Введите размерность СЛАУ: ";

cin >> size;

// выделяем память под матрицу системы

double ** rows = new double*[size];

for (int i = 0; i < size; i++)

rows[i] = new double[size + 1];

cout << "Введите построчно элементы матрицы СЛАУ" << endl;

for (int i = 0; i < size; i++)

{

for (int j = 0; j <= size; j++)

{

//cout << "A[" << i + 1 << "][" << j + 1 << "] = ";

cin >> rows[i][j];

}

}

//cout << "Введите элементы столбца b в правой части СЛАУ" << endl;

//for (int i = 0; i < size; i++)

//{

// cout << "b[" << i + 1 << "] = ";

// cin >> rows[i][size];

//}

cout << "Система заполнена" << endl;

for (int i = 0; i < size; i++)

{

for (int j = 0; j <= size; j++)

cout << setw(4) << rows[i][j];

cout << endl;

}

cout << endl;

// массив для корней системы

double *x = new double[size];

// переменные для вычисления времени выполнения

__int64 timerFreq, counterAtStart, counterAtStop;

double duration;

// засекаем время начала вычислений

QueryPerformanceFrequency((LARGE_INTEGER*)&timerFreq);

QueryPerformanceCounter((LARGE_INTEGER*)&counterAtStart);

// решаем систему методом Крамера (определителей)

Kramer(rows, x, size);

QueryPerformanceCounter((LARGE_INTEGER*)&counterAtStop);

duration = (double)(counterAtStop - counterAtStart) / timerFreq;

cout << "Время выполнения: " << duration << " мс" << endl;

// выводим резулльтат на экран

cout << endl << "Решение СЛАУ" << endl;

for (int i = 0; i < size; i++)

cout << "x[" << i + 1 << "] = " << x[i] << endl;

// освобождаем память

for (size_t i = 0; i < size; i++)

delete[] rows[i];

delete[] rows;

delete[] x;

system("Pause");

return 0;

}

Результат:

Задание 2:

Решить линейное уравнение методом Гаусса.

Пример из книги:

#include <iostream>

#include <iomanip>

#include <Windows.h>

using namespace std;

// решение СЛАУ методом Гаусса

void Gauss(double** A, double* x, int size)

{

double tmp;

int opCount1 = 0; // счётчик операций (умножение и деление)

int opCount2 = 0; // счётчик операций (сложение и вычитание)

// прямой проход

for (int i = 0; i < size; i++)

{

tmp = A[i][i];

for (int j = i; j <= size; j++)

{

A[i][j] /= tmp;

opCount1++;

}

for (int k = i + 1; k < size; k++)

{

tmp = A[k][i];

for (int j = i; j <= size; j++)

{

A[k][j] -= tmp * A[i][j];

opCount1++;

opCount2++;

}

}

}

// обратный проход

for (int i = size - 1; i >= 0; i--)

{

tmp = A[i][size];

for (int j = i + 1; j < size; j++)

{

tmp -= A[i][j] * x[j];

opCount1++;

opCount2++;

}

x[i] = tmp / A[i][i];

opCount1++;

}

cout << "Вычисление методом Гаусса завершено" << endl

<< "выполнено " << opCount1 + opCount2 << " арифметических операций, их них:" << endl;

cout << "операций умножения и деления - " << opCount1 << endl;

cout << "операций сложения и вычитания - " << opCount2 << endl;

}

int main()

{

setlocale(LC_ALL, "Russian");

// матрица СЛАУ

double src[][5] = {

{ 2, 1, -5, 1, 8},

{ 1, -3, 0, -6, 9},

{ 0, 2, -1, 2, -5},

{ 1, 4, -7, 6, 0}

};

// создаём и заполняем динамический массив указателей на строки

// для работы с матрицей системы

const int size = sizeof(src) / sizeof(src[0]);

double** rows = new double*[size];

for (size_t i = 0; i < size; i++)

rows[i] = src[i];

//int size = 0;

//cout << "Введите размерность СЛАУ: ";

//cin >> size;

//// выделяем память под матрицу системы

//double** rows = new double* [size];

//for (int i = 0; i < size; i++)

// rows[i] = new double[size + 1];

//cout << "Введите построчно элементы матрицы СЛАУ" << endl;

//for (int i = 0; i < size; i++)

//{

// for (int j = 0; j <= size; j++)

// {

// //cout << "A[" << i + 1 << "][" << j + 1 << "] = ";

// cin >> rows[i][j];

// }

//}

cout << "Система заполнена" << endl;

for (int i = 0; i < size; i++)

{

for (int j = 0; j <= size; j++)

cout << setw(4) << rows[i][j];

cout << endl;

}

cout << endl;

// массив для корней системы

double* x = new double[size];

// переменные для вычисления времени выполнения

__int64 timerFreq, counterAtStart, counterAtStop;

double duration;

// засекаем время начала вычислений

QueryPerformanceFrequency((LARGE_INTEGER*)&timerFreq);

QueryPerformanceCounter((LARGE_INTEGER*)&counterAtStart);

// решаем систему методом Гаусса

Gauss(rows, x, size);

QueryPerformanceCounter((LARGE_INTEGER*)&counterAtStop);

duration = (double)(counterAtStop - counterAtStart) / timerFreq;

cout << "Время выполнения: " << duration << " мс" << endl;

// выводим резулльтат на экран

cout << endl << "Решение СЛАУ" << endl;

for (int i = 0; i < size; i++)

cout << "x[" << i + 1 << "] = " << x[i] << endl;

// освобождаем память

//for (size_t i = 0; i < size; i++)

// delete[] rows[i];

delete[] rows;

delete[] x;

system("Pause");

return 0;

}

Результат:

Сама программа решения линейного уравнения методом Гаусса:

#include <iostream>

#include <iomanip>

#include <Windows.h>

using namespace std;

// решение СЛАУ методом Гаусса

void Gauss(double** A, double* x, int size)

{

double tmp;

int opCount1 = 0; // счётчик операций (умножение и деление)

int opCount2 = 0; // счётчик операций (сложение и вычитание)

// прямой проход

for (int i = 0; i < size; i++)

{

tmp = A[i][i];

for (int j = i; j <= size; j++)

{

A[i][j] /= tmp;

opCount1 ++;

}

for (int k = i + 1; k < size; k++)

{

tmp = A[k][i];

for (int j = i; j <= size; j++)

{

A[k][j] -= tmp * A[i][j];

opCount1 ++;

opCount2 ++;

}

}

}

// обратный проход

for (int i = size - 1; i >= 0; i--)

{

tmp = A[i][size];

for (int j = i + 1; j < size; j++)

{

tmp -= A[i][j] * x[j];

opCount1++;

opCount2++;

}

x[i] = tmp / A[i][i];

opCount1++;

}

cout << "Вычисление методом Гаусса завершено" << endl

<< "выполнено " << opCount1 + opCount2 << " арифметических операций, их них:" << endl;

cout << "операций умножения и деления - " << opCount1 << endl;

cout << "операций сложения и вычитания - " << opCount2 << endl;

}

int main()

{

setlocale(LC_ALL, "Russian");

//// матрица СЛАУ

//double src[][5] = {

// { 2, 1, -5, 1, 8},

// { 1, -3, 0, -6, 9},

// { 0, 2, -1, 2, -5},

// { 1, 4, -7, 6, 0}

//};

//// создаём и заполняем динамический массив указателей на строки

//// для работы с матрицей системы

//const int size = sizeof(src) / sizeof(src[0]);

//double** rows = new double* [size];

//for (size_t i = 0; i < size; i++)

// rows[i] = src[i];

int size = 0;

cout << "Введите размерность СЛАУ: ";

cin >> size;

// выделяем память под матрицу системы

double** rows = new double* [size];

for (int i = 0; i < size; i++)

rows[i] = new double[size + 1];

cout << "Введите построчно элементы матрицы СЛАУ" << endl;

for (int i = 0; i < size; i++)

{

for (int j = 0; j <= size; j++)

{

//cout << "A[" << i + 1 << "][" << j + 1 << "] = ";

cin >> rows[i][j];

}

}

//cout << "Введите элементы столбца b в правой части СЛАУ" << endl;

//for (int i = 0; i < size; i++)

//{

// cout << "b[" << i + 1 << "] = ";

// cin >> rows[i][size];

//}

cout << "Система заполнена" << endl;

for (int i = 0; i < size; i++)

{

for (int j = 0; j <= size; j++)

cout << setw(4) << rows[i][j];

cout << endl;

}

cout << endl;

// массив для корней системы

double* x = new double[size];

// переменные для вычисления времени выполнения

__int64 timerFreq, counterAtStart, counterAtStop;

double duration;

// засекаем время начала вычислений

QueryPerformanceFrequency((LARGE_INTEGER*)&timerFreq);

QueryPerformanceCounter((LARGE_INTEGER*)&counterAtStart);

// решаем систему методом Гаусса

Gauss(rows, x, size);

QueryPerformanceCounter((LARGE_INTEGER*)&counterAtStop);

duration = (double)(counterAtStop - counterAtStart) / timerFreq;

cout << "Время выполнения: " << duration << " мс" << endl;

// выводим резулльтат на экран

cout << endl << "Решение СЛАУ" << endl;

for (int i = 0; i < size; i++)

cout << "x[" << i + 1 << "] = " << x[i] << endl;

// освобождаем память

for (size_t i = 0; i < size; i++)

delete[] rows[i];

delete[] rows;

delete[] x;

system("Pause");

return 0;

}

Результат:

Выводы: были разработаны пользовательские алгоритмы и программы для решения линейных уравнений двумя разными методами, такими как: метод Крамера и метод Гаусса. Также были приобретены навыки и умения анализа алгоритма. Во всех программах при одной и той же матрице ответ совпадает: х1=3, х2=-4, х3=-1, х4=1.

Содержание

Основная часть 2

Результаты выполнения работы 2

Выводы 14

Содержание 14

САНКТ-ПЕТЕРБУРГ 2020