Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- #include <string>
- // Улучшение класса матриц, с exception, операциями с матрицами и теперь с double вместо int
- // теперь с нормальной асимптотикой поиска определителя матрицы
- using namespace std;
- // Исключение для разных размерностей матриц
- class Error_invalid_size {
- string message;
- public:
- Error_invalid_size() : message("Разные размерности!") {}
- ~Error_invalid_size() {}
- void what() {
- cout << message << endl;
- }
- };
- // Исключение для неквадратных матриц
- class Error_non_square_matrix {
- string message;
- public:
- Error_non_square_matrix() : message("Матрица не квадратная!") {}
- ~Error_non_square_matrix() {}
- void what() {
- cout << message << endl;
- }
- };
- // Исключение для матриц, не являющихся положительно определенными
- class Error_not_positive_definite {
- string message;
- public:
- Error_not_positive_definite() : message("Матрица не является положительно определенной!") {}
- ~Error_not_positive_definite() {}
- void what() {
- cout << message << endl;
- }
- };
- class Matrix {
- private:
- double** matrix;
- int rows;
- int cols;
- double my_abs(double x) {
- return x >= 0 ? x : -x;
- }
- // Для поиска квадратных корней
- double my_sqrt(double x) {
- if (x < 0) {
- return 0;
- }
- double guess = x / 2.0;
- double epsilon = 1e-10;
- while (my_abs(guess * guess - x) > epsilon) {
- guess = (guess + x / guess) / 2.0;
- }
- return guess;
- }
- public:
- Matrix(int new_rows, int new_cols) {
- this->rows = new_rows;
- this->cols = new_cols;
- this->matrix = new double*[new_rows];
- for (int i = 0; i < this->rows; ++i) {
- matrix[i] = new double[new_cols];
- }
- for (int i = 0; i < this->rows; ++i) {
- for (int j = 0; j < this->cols; ++j) {
- matrix[i][j] = 0.0;
- }
- }
- }
- Matrix(const Matrix& other) {
- rows = other.rows;
- cols = other.cols;
- matrix = new double*[rows];
- for (int i = 0; i < rows; ++i) {
- matrix[i] = new double[cols];
- for (int j = 0; j < cols; ++j) {
- matrix[i][j] = other.matrix[i][j];
- }
- }
- }
- ~Matrix() {
- for (int i = 0; i < this->rows; ++i) {
- delete[] this->matrix[i];
- }
- delete[] this->matrix;
- }
- Matrix operator+ (const Matrix& other) {
- if (this->rows != other.rows || this->cols != other.cols) {
- throw Error_invalid_size();
- }
- Matrix new_matrix(this->rows, this->cols);
- for (int i = 0; i < this->rows; ++i) {
- for (int j = 0; j < this->cols; ++j) {
- new_matrix.matrix[i][j] = this->matrix[i][j] + other.matrix[i][j];
- }
- }
- return new_matrix;
- }
- Matrix operator- (const Matrix& other) {
- if (this->rows != other.rows || this->cols != other.cols) {
- throw Error_invalid_size();
- }
- Matrix new_matrix(this->rows, this->cols);
- for (int i = 0; i < this->rows; ++i) {
- for (int j = 0; j < this->cols; ++j) {
- new_matrix.matrix[i][j] = this->matrix[i][j] - other.matrix[i][j];
- }
- }
- return new_matrix;
- }
- Matrix operator* (const Matrix& other) {
- if (this->cols != other.rows) {
- throw Error_invalid_size();
- }
- Matrix result(this->rows, other.cols);
- for (int i = 0; i < this->rows; ++i) {
- for (int j = 0; j < other.cols; ++j) {
- result.matrix[i][j] = 0.0;
- for (int k = 0; k < this->cols; ++k) {
- result.matrix[i][j] += this->matrix[i][k] * other.matrix[k][j];
- }
- }
- }
- return result;
- }
- Matrix operator* (double scalar) {
- Matrix new_matrix(this->rows, this->cols);
- for (int i = 0; i < this->rows; ++i) {
- for (int j = 0; j < this->cols; ++j) {
- new_matrix.matrix[i][j] = this->matrix[i][j] * scalar;
- }
- }
- return new_matrix;
- }
- friend Matrix operator* (double scalar, const Matrix& mat) {
- Matrix new_matrix(mat.rows, mat.cols);
- for (int i = 0; i < mat.rows; ++i) {
- for (int j = 0; j < mat.cols; ++j) {
- new_matrix.matrix[i][j] = scalar * mat.matrix[i][j];
- }
- }
- return new_matrix;
- }
- // Произведение Адамара
- Matrix operator% (const Matrix& other) {
- if (this->rows != other.rows || this->cols != other.cols) {
- throw Error_invalid_size();
- }
- Matrix new_matrix(this->rows, this->cols);
- for (int i = 0; i < this->rows; ++i) {
- for (int j = 0; j < this->cols; ++j) {
- new_matrix.matrix[i][j] = this->matrix[i][j] * other.matrix[i][j];
- }
- }
- return new_matrix;
- }
- Matrix transpose() {
- Matrix new_matrix(this->cols, this->rows);
- for (int i = 0; i < this->rows; ++i) {
- for (int j = 0; j < this->cols; ++j) {
- new_matrix.matrix[j][i] = this->matrix[i][j];
- }
- }
- return new_matrix;
- }
- double determinant() {
- if (this->rows != this->cols) {
- throw Error_non_square_matrix();
- }
- int n = this->rows;
- // Сохраняем исходные данные
- double** mat_copy = new double*[n];
- for (int i = 0; i < n; i++) {
- mat_copy[i] = new double[n];
- for (int j = 0; j < n; j++) {
- mat_copy[i][j] = this->matrix[i][j];
- }
- }
- double det = 1.0;
- int sign = 1;
- for (int k = 0; k < n; k++) {
- // Частичный поворот для численной стабильности
- double max = my_abs(mat_copy[k][k]);
- int maxRow = k;
- for (int i = k + 1; i < n; i++) {
- if (my_abs(mat_copy[i][k]) > max) {
- max = my_abs(mat_copy[i][k]);
- maxRow = i;
- }
- }
- // Если опорный элемент равен нулю, то определитель равен нулю
- if (mat_copy[maxRow][k] == 0) {
- det = 0.0;
- break;
- }
- // Swap rows if needed
- if (maxRow != k) {
- double* temp = mat_copy[k];
- mat_copy[k] = mat_copy[maxRow];
- mat_copy[maxRow] = temp;
- sign *= -1;
- }
- // Исключяем ниже точки разворота
- for (int i = k + 1; i < n; i++) {
- double factor = mat_copy[i][k] / mat_copy[k][k];
- mat_copy[i][k] = 0.0;
- for (int j = k + 1; j < n; j++) {
- mat_copy[i][j] -= factor * mat_copy[k][j];
- }
- }
- }
- if (det != 0.0) {
- // Умножаем диагональные элементы
- for (int i = 0; i < n; i++) {
- det *= mat_copy[i][i];
- }
- det *= sign;
- }
- // Чистим память
- for (int i = 0; i < n; i++) {
- delete[] mat_copy[i];
- }
- delete[] mat_copy;
- return det;
- }
- // След матрицы
- double trace() {
- if (this->rows != this->cols) {
- throw Error_non_square_matrix();
- }
- double sum = 0.0;
- for (int i = 0; i < this->rows; ++i) {
- sum += this->matrix[i][i];
- }
- return sum;
- }
- // Разложение Холецкого
- Matrix cholesky() {
- if (this->rows != this->cols) {
- throw Error_non_square_matrix();
- }
- int n = this->rows;
- Matrix L(n, n);
- for (int i = 0; i < n; i++) {
- for (int j = 0; j <= i; j++) {
- double sum = 0.0;
- if (j == i) {
- for (int k = 0; k < j; k++) {
- sum += L.matrix[j][k] * L.matrix[j][k];
- }
- double val = this->matrix[j][j] - sum;
- if (val <= 0) {
- throw Error_not_positive_definite();
- }
- L.matrix[j][j] = my_sqrt(val);
- } else {
- for (int k = 0; k < j; k++) {
- sum += L.matrix[i][k] * L.matrix[j][k];
- }
- L.matrix[i][j] = (1.0 / L.matrix[j][j]) * (this->matrix[i][j] - sum);
- }
- L.matrix[j][i] = 0.0; // Обеспечиваем нули в верхней треугольной части
- }
- }
- return L;
- }
- double get(int i, int j) const {
- if (i < 0 || i >= this->rows || j < 0 || j >= this->cols) {
- throw std::out_of_range("Индекс вне диапазона!");
- }
- return this->matrix[i][j];
- }
- void set(int i, int j, double value) {
- if (i < 0 || i >= this->rows || j < 0 || j >= this->cols) {
- throw std::out_of_range("Индекс вне диапазона!");
- }
- this->matrix[i][j] = value;
- }
- // Поиск обратной матрицы
- Matrix invert() {
- if (this->rows != this->cols) {
- throw Error_non_square_matrix();
- }
- int n = this->rows;
- Matrix aug(n, 2 * n);
- // Расширенная матрица [A | I]
- for (int i = 0; i < n; i++) {
- for (int j = 0; j < n; j++) {
- aug.set(i, j, this->get(i, j));
- }
- for (int j = n; j < 2 * n; j++) {
- aug.set(i, j, (i == j - n) ? 1.0 : 0.0);
- }
- }
- // Исключения по Гауссу-Джордану
- for (int i = 0; i < n; i++) {
- // Точка опоры
- double pivot = aug.get(i, i);
- if (pivot == 0) {
- throw std::runtime_error("Матрица является вырожденной и не может быть инвертирована.");
- }
- // Нормализуем
- for (int j = 0; j < 2 * n; j++) {
- aug.set(i, j, aug.get(i, j) / pivot);
- }
- // Убираем другие строки
- for (int k = 0; k < n; k++) {
- if (k != i) {
- double factor = aug.get(k, i);
- for (int j = 0; j < 2 * n; j++) {
- aug.set(k, j, aug.get(k, j) - factor * aug.get(i, j));
- }
- }
- }
- }
- // Извлекаем обратную матрицу
- Matrix inv(n, n);
- for (int i = 0; i < n; i++) {
- for (int j = n; j < 2 * n; j++) {
- inv.set(i, j - n, aug.get(i, j));
- }
- }
- return inv;
- }
- void print() const {
- for (int i = 0; i < this->rows; ++i) {
- for (int j = 0; j < this->cols; ++j) {
- cout << matrix[i][j] << ' ';
- }
- cout << '\n';
- }
- }
- };
- int main() {
- try {
- Matrix mat1(2, 2);
- mat1.set(0, 0, 4.0);
- mat1.set(0, 1, 12.0);
- mat1.set(1, 0, 12.0);
- mat1.set(1, 1, 37.0);
- Matrix mat2(2, 2);
- mat2.set(0, 0, 3.0);
- mat2.set(0, 1, 4.0);
- mat2.set(1, 0, 5.0);
- mat2.set(1, 1, 6.0);
- Matrix sum = mat1 + mat2;
- cout << "Сумма:\n";
- sum.print();
- Matrix diff = mat1 - mat2;
- cout << "Разность:\n";
- diff.print();
- Matrix prod = mat1 * mat2;
- cout << "Умножение:\n";
- prod.print();
- Matrix scalar_mul = mat1 * 2.0;
- cout << "Скалярное произведение на 2:\n";
- scalar_mul.print();
- Matrix hadamard = mat1 % mat2;
- cout << "Произведение Адамара:\n";
- hadamard.print();
- Matrix transposed = mat1.transpose();
- cout << "Транспонирование:\n";
- transposed.print();
- double det = mat1.determinant();
- cout << "Определитель: " << det << endl;
- double tr = mat1.trace();
- cout << "След: " << tr << endl;
- Matrix chol = mat1.cholesky();
- cout << "Разложение Холецкого:\n";
- chol.print();
- Matrix inv = mat1.invert();
- cout << "Обратная матрица:\n";
- inv.print();
- } catch (Error_invalid_size& e) {
- e.what();
- } catch (Error_non_square_matrix& e) {
- e.what();
- } catch (Error_not_positive_definite& e) {
- e.what();
- } catch (std::exception& e) {
- cout << e.what() << endl;
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement