https://pastein.ru/t/s0L
скопируйте уникальную ссылку для отправки
Загрузка данных
#include <iostream>
#include <vector>
#include <cmath>
#include <ctime>
#include <cstdlib>
#include <iomanip>
using namespace std;
const int MATR_PREC = 1; // precision when printing matrices
const int PREC = 8; // precision when printing floating point numbers
/*
Написать программу, которая решает систему Ax = b указанными в варианте методами
Решить систему с помощью метода Гаусса с выбором ведущего элемента по столбцу и методом квадратного корня (Холецкого), найти определитель матрицы А.
a[i,i] = 5i
a[i,j] = 0.1ij
i != j
i, j = 1..n
N = 15
Вектор b задается случайным образом.
Реализовать проверку правильности написанной программы: выводить норму невязки полученного решения, для LU- и QR-разложений выводить значение нормы или и т.д. Нормы можно выбирать любые (указать, какие).
Программы должны быть реализованы с максимально возможной экономией памяти и/или количества операций
*/
vector<vector<float> > generate_matr(int n = 15){
vector<vector<float> > matr(n, vector<float>(n));
for(int i = 0; i < n; i++){
matr[i][i] = 5 * (i + 1);
for(int j = 0; j < n; j++)
if(i != j)
matr[i][j] = 0.1 * (i + 1) * (j + 1);
}
return matr;
}
void print_matr(vector<vector<float> >& a, vector<float>& b, int max_rows = 10, int max_cols = 10){
// set fixed notation
cout << fixed << setprecision(MATR_PREC);
int n = a.size();
for(int i = 0; i < min(n, max_rows); i++){
for(int j = 0; j < min(n, max_cols); j++)
cout << setw(5) << a[i][j] << " ";
// if to many columns, print "..."
if(n > max_cols)
cout << " ...";
cout << " | " << b[i] << endl;
}
// if to many rows, print "..."
if(n > max_rows){
for(int i = 0; i < max_cols; i++)
cout << setw(5) << "..." << " ";
if(n > max_cols)
cout << " ...";
cout << " | ..." << endl;
}
cout << endl;
// back to normal precision
cout << fixed << setprecision(PREC);
}
// метод для расчета и вывода нормы невязки
// используется максимум-норма
void print_norm(const vector<vector<float> >& a, const vector<float>& b, const vector<float>& x){
int n = a.size();
float max_norm = 0;
for(int i = 0; i < n; i++){
float sum = 0;
for(int j = 0; j < n; j++)
sum += a[i][j] * x[j];
max_norm = max(max_norm, fabs(sum - b[i]));
// cout << sum << " - " << b[i] << " = " << fabs(sum - b[i]) << endl;
}
cout << "Норма невязки(максимум-норма): " << max_norm << endl;
}
// метод для рассчета СЛАУ по методу Гаусса
void gauss(int n, const vector<vector<float> >& const_a, const vector<float>& const_b){
auto a = const_a;
auto b = const_b;
vector<float> x(n);
// прямой ход
// k - номер строки
for(int k = 0; k < n - 1; k++){
// выбор ведущего элемента по столбцу
int e_max = k;
for(int i = k + 1; i < n; i++)
if(fabs(a[i][k]) > fabs(a[e_max][k]))
e_max = i;
// меняем местами k-ую и e_max-ую строки
swap(a[k], a[e_max]);
swap(b[k], b[e_max]);
// i - номер строки, из которой вычитают k-ую строку
for(int i = k + 1; i < n; i++){
float m = a[i][k] / a[k][k];
for(int j = k; j < n; j++)
a[i][j] -= m * a[k][j];
b[i] -= m * b[k];
}
}
// обратный ход
for(int k = n - 1; k >= 0; k--){
x[k] = b[k];
for(int i = k + 1; i < n; i++)
x[k] -= a[k][i] * x[i];
x[k] /= a[k][k];
}
cout << "Метод Гаусса" << endl;
for(int i = 0; i < n; i++)
cout << x[i] << " ";
cout << endl;
// выводим норму невязки
print_norm(const_a, const_b, x);
}
void transform_matrix_to_U(int n, vector<vector<float> >& g){
// найдем матрицу U из прямого хода метода Гаусса
for(int k = 0; k < n - 1; k++){
for(int i = k + 1; i < n; i++){
float m = g[i][k] / g[k][k];
for(int j = k; j < n; j++)
g[i][j] -= m * g[k][j];
}
}
}
// метод для рассчета СЛАУ по методу квадратного корня (Холецкого)
// (это возможно только для симметричных положительно определенных матриц)
void cholesky(int n, const vector<vector<float> >& const_a, const vector<float>& const_b){
// A = G * G^T, где G - нижнетреугольная матрица
auto g = const_a;
// найдем матрицу U из прямого хода метода Гаусса
transform_matrix_to_U(n, g);
// домножаем элементы на корни диагональных
for(int i = 0; i < n; i++){
float sqrt_elem = sqrt(g[i][i]);
for(int j = 0; j < n; j++)
g[i][j] /= sqrt_elem;
}
// транспонируем матрицу
for(int i = 0; i < n; i++)
for(int j = i + 1; j < n; j++)
swap(g[i][j], g[j][i]);
// решаем систему G * y = b методом Гаусса
vector<float> y(n);
y[0] = const_b[0] / g[0][0];
for(int i = 1; i < n; i++){
float sum = 0;
for(int j = 0; j < i; j++)
sum += g[i][j] * y[j];
y[i] = (const_b[i] - sum) / g[i][i];
}
// решаем систему G^T * x = y методом Гаусса
vector<float> x(n);
x[n-1] = y[n-1] / g[n-1][n-1];
for(int i = n - 2; i >= 0; i--){
float sum = 0;
for(int j = i + 1; j < n; j++)
sum += g[j][i] * x[j];
x[i] = (y[i] - sum) / g[i][i];
}
cout << "Метод квадратного корня (Холецкого)" << endl;
for(int i = 0; i < n; i++)
cout << x[i] << " ";
cout << endl;
// выводим норму невязки
print_norm(const_a, const_b, x);
}
// метод для рассчета определителя матрицы
// воспользуемся преобразованием матрицы к верхнетреугольному виду
float det(int n, const vector<vector<float> >& const_a){
auto matr = const_a;
transform_matrix_to_U(n, matr);
float det = 1;
for(int i = 0; i < n; i++)
det *= matr[i][i];
return det;
}
int main(){
srand(time(nullptr)); // NOLINT(cert-msc51-cpp)
cout << fixed << setprecision(PREC);
// исходные векторы, не изменяются, только копируются
int n = 15;
vector<vector<float> > a = generate_matr(n);
vector<float> b(n);
for(int i = 0; i < n; i++)
b[i] = rand() % 10000; // NOLINT(cert-msc50-cpp,cppcoreguidelines-narrowing-conversions)
cout << "Исходная СЛАУ(обрезана до 10 строк/столбцов):" << endl;
print_matr(a, b);
// метод Гаусса
auto start_time = clock();
gauss(n, a, b);
cout << "Итоговое время: " << (double)(clock() - start_time) / CLOCKS_PER_SEC << endl << endl;
// метод квадратного корня (Холецкого)
start_time = clock();
cholesky(n, a, b);
cout << "Итоговое время: " << (double)(clock() - start_time) / CLOCKS_PER_SEC << endl << endl;
// считаем определитель матрицы
// должно выйти 10911135640586240917504 (вроде)
float perfect_det = 10911135640586240917504.;
float r_det = det(n, a);
cout << "Определитель матрицы: " << r_det << endl;
cout << "Точное значение определителя: " << perfect_det << endl;
cout << "Абсолютная погрешность: " << fabs(r_det - perfect_det) << endl;
cout << "Относительная погрешность: " << fabs(r_det - perfect_det) / perfect_det * 100 << "%" << endl;
return 0;
}