Скачиваний:
36
Добавлен:
10.09.2019
Размер:
15.52 Кб
Скачать
#include <cmath>
#include <iostream>
#include <stdexcept>

using std::cin;
using std::cout;
using std::endl;

// Класс «Матрица»
class SimpleMatrix {
 private:
    // Количество строк
    size_t n_;
    // Количество столбцов
    size_t m_;
    // Указатель на указатель
    double **values_ = nullptr;

 public:
    // Конструкторы
    // Для матрицы N (строк) на M (столбцов)
    explicit SimpleMatrix(size_t n, size_t m) : n_(n), m_(m) {
        if (n > 0 && m > 0) {
            values_ = new double *[n]; // Выделяем память для строк
            for (size_t i = 0; i < n; ++i) {
                values_[i] = new double[m] {0}; // Для столбцов
            }
        }
    }

    // Для квадратной (м. б. единичной) матрицы
    explicit SimpleMatrix(size_t n, bool isIdentity = false) : n_(n), m_(n) {
        if (n > 0 && m_ > 0) {
            values_ = new double *[n]; // Выделяем память для строк
            for (size_t i = 0; i < n; ++i) {
                values_[i] = new double[m_] {0},
                    values_[i][i] = 1; // Для столбцов; элементы главной диагонали = 1
            }
        }
    }

    // Конструктор копирования
    SimpleMatrix(const SimpleMatrix &arg) : n_(arg.n_), m_(arg.m_) {
        values_ = new double *[n_]; // Выделяем память для строк
        for (size_t i = 0; i < n_; ++i) {
            values_[i] = new double[m_]; // Для столбцов
            std::copy(arg.values_[i], arg.values_[i] + m_, values_[i]); // Копируем очередную строку из arg в текущую
        }
    }

    // Оператор копирования
    SimpleMatrix &operator=(const SimpleMatrix &arg) {
        SimpleMatrix temp(arg); // Создаем копию arg
        swap(*this, temp); // Меняем местами уже существующий this и копию arg; temp после return уничтожится
        return *this;
    }

    // Конструктор перемещения
    SimpleMatrix(SimpleMatrix &&arg) noexcept {
        values_ = arg.values_, n_ = arg.n_, m_ = arg.m_; // Перемещаем данные из arg
        arg.values_ = nullptr, arg.n_ = arg.m_ = 0; // Заполняем поля arg 'нулевыми' значениями
    }

    // Оператор перемещения
    SimpleMatrix &operator=(SimpleMatrix &&arg) noexcept {
        if (this != &arg) { // Если мы не пытаемся переместить себя в себя так: MyObject = std::move(MyObject);
            swap(*this, arg); // Меняем местами this и arg
            if (arg.values_) { // Освобождаем память arg (которая ранее была в this), если она имелась
                for (size_t i = 0; i < arg.n_; ++i) {
                    delete[] arg.values_[i];
                }
                delete[] arg.values_;
                arg.values_ = nullptr, arg.n_ = arg.m_ = 0; // Заполняем поля arg 'нулевыми' значениями
            }
        }
        return *this;
    }

    // Деструктор
    virtual ~SimpleMatrix() {
        for (size_t i = 0; i < n_; ++i) {
            delete[] values_[i];
        }
        delete[] values_; // Если values_ = nullptr, то delete[] не приведет к ошибке
    }

    // Очистка матрицы
    void clear() {
        for (size_t i = 0; i < n_; ++i) {
            delete[] values_[i];
        }
        delete[] values_;
        values_ = nullptr, n_ = m_ = 0;
    }

    // Получение строки матрицы по индексу (не вызывает исключения)
    double *operator[](size_t idx) {
        return values_[idx]; // Возвращаем строку (Обращение к элементу строки i столбца j: values_[idx][idx2])
    }

    // Число строк матрицы
    size_t N() const { return n_; }

    // Число столбцов матрицы
    size_t M() const { return m_; }

    // Сложение матриц
    SimpleMatrix operator+(const SimpleMatrix &arg) const noexcept(false) {
        if (n_ == arg.n_ && m_ == arg.m_) { // Сложение возможно, если только размеры матриц равны
            SimpleMatrix result(*this); // Копируем данные из *this в result (конструктор копирования)
            for (size_t i = 0; i < n_; ++i) {
                for (size_t j = 0; j < m_; ++j) {
                    result.values_[i][j] += arg.values_[i][j]; // В result копия данных this складывается с данными arg
                }
            }
            return result;
        }
        throw std::invalid_argument("N != ARG.N || M != ARG.M");
    }

    // Вычитание матриц
    SimpleMatrix operator-(const SimpleMatrix &arg) const {
        return ( *this + ( -arg ) ); // Используем уже существующий оператор сложения с матрицей
    }

    // Смена знака элементов матрицы
    SimpleMatrix operator-() const {
        SimpleMatrix result(*this); // Копируем данные из *this в result (конструктор копирования)
        for (size_t i = 0; i < n_; ++i) {
            for (size_t j = 0; j < m_; ++j) {
                result.values_[i][j] = -result.values_[i][j];
            }
        }
        return result;
    }

    // Умножение матриц
    SimpleMatrix operator*(const SimpleMatrix &arg) const noexcept(false) {
        if (m_ == arg.n_) { // Если число стб. матрицы this совпадает с числом стр. матрицы arg, то умножение возможно
            SimpleMatrix result(this->n_, arg.m_); // Конструктор по размерам
            for (size_t i = 0; i < n_; ++i) {
                for (size_t j = 0; j < arg.m_; ++j) {
                    for (size_t k = 0; k < m_; ++k) {
                        result.values_[i][j] += values_[i][k] * arg.values_[k][j];
                    }
                }
            }
            return result;
        }
        throw std::invalid_argument("The number of columns of matrix A is not equal to the number of rows of matrix B");
    }

    // Умножение всех элементов матрицы на заданное число
    SimpleMatrix operator*(const double &d) const {
        SimpleMatrix result(*this); // Копируем данные из *this в result (конструктор копирования)
        for (size_t i = 0; i < n_; ++i) {
            for (size_t j = 0; j < m_; ++j) {
                result.values_[i][j] *= d;
            }
        }
        return result;
    }

    // Деление всех элементов матрицы на заданное число
    SimpleMatrix operator/(const double &d) const {
        return ( *this * ( 1. / d ) ); // Используем уже существующий оператор умножения на число
    }

    // Сумма элементов k-той строки
    double sumString(size_t k) const noexcept(false) {
        if (k >= 0 && k < n_) { // Если k-тая строка имеется, то вычисляем сумму
            double s = 0;
            for (size_t j = 0; j < m_; ++j) {
                s += values_[k][j];
            }
            return s;
        }
        throw std::out_of_range("SimpleMatrix. Method sumString. Out of range");
    }

    // Сумма элементов k-того столбца
    double sumColumn(size_t k) const noexcept(false) {
        if (k >= 0 && k < m_) { // Если k-тый столбец имеется, то вычисляем сумму
            double s = 0;
            for (size_t i = 0; i < n_; ++i) {
                s += values_[i][k];
            }
            return s;
        }
        throw std::out_of_range("SimpleMatrix. Method sumColumn. Out of range");
    }

    // Транспонирование матрицы
    SimpleMatrix transpose() const {
        SimpleMatrix result(m_, n_); // При транспонировании n становится m, m становится n
        for (size_t i = 0; i < n_; ++i) {
            for (size_t j = 0; j < m_; ++j) {
                result.values_[j][i] = values_[i][j];
            }
        }
        return result;
    }

    // Применение функции func к каждому элементу матрицы
    SimpleMatrix doForEach(double (*func)(double)) const {
        SimpleMatrix result(*this); // Копируем данные из *this в result (конструктор копирования)
        for (size_t i = 0; i < n_; ++i) {
            for (size_t j = 0; j < m_; ++j) {
                result.values_[i][j] = func(result.values_[i][j]); // Применяем к каждому элементу функцию func
            }
        }
        return result;
    }

    // Равны ли две матрицы?
    bool operator==(const SimpleMatrix &arg) const {
        if (n_ != arg.n_ && m_ != arg.m_) {
            return false;
        }
        for (size_t i = 0; i < n_; ++i) {
            for (size_t j = 0; j < m_; ++j) {
                if (this->values_[i][j] != arg.values_[i][j]) {
                    return false;
                }
            }
        }
        return true;
    }

    // Не равны ли две матрицы?
    bool operator!=(const SimpleMatrix &arg) const {
        return !( *this == arg );
    }

    // Оператор приведения к типу bool
    explicit operator bool() {
        return n_ != 0 && m_ != 0;
    }

    // Дружественный оператор для вывода матрицы в выходной поток os (cout, ...)
    friend std::ostream &operator<<(std::ostream &os, const SimpleMatrix &arg) {
        for (size_t i = 0; i < arg.n_; ++i) {
            os << arg.values_[i][0];
            for (size_t j = 1; j < arg.m_; ++j) {
                os << ' ' << arg.values_[i][j];
            }
            os << '\n';
        }
        return os;
    }

    friend void swap(SimpleMatrix &first, SimpleMatrix &second) noexcept {
        std::swap(first.values_, second.values_);
        std::swap(first.m_, second.m_);
        std::swap(first.n_, second.n_);
    }
};

int main() {
    const size_t N1 = 2, N2 = 5;
    // Создание матриц
    SimpleMatrix massA(N1, N2), massB(N2, N1);
    // Вывод матрицы и её размеров
    cout << "Matrix A:\n" << massA << "(size: " << massA.N() << " x " << massA.M() << ')' << endl;
    cout << "Matrix B:\n" << massB << "(size: " << massB.N() << " x " << massB.M() << ')' << endl << endl;
    // Заполнение матрицы
    for (size_t i = 0; i < N1; ++i) {
        for (size_t j = 0; j < N2; ++j) {
            massA[i][j] = rand() % 100;
            massB[j][i] = rand() % 100;
        }
    }
    // Вывод матрицы
    cout << "Matrix A:\n" << massA << "(size: " << massA.N() << " x " << massA.M() << ')' << endl;
    cout << "Matrix B:\n" << massB << "(size: " << massB.N() << " x " << massB.M() << ')' << endl << endl;
    // Конструктор копирования
    SimpleMatrix massC(massB);
    cout << "1. Copy constructor:" << endl;
    cout << "Matrix B:\n" << massB << "(size: " << massB.N() << " x " << massB.M() << ')' << endl;
    cout << "Matrix C:\n" << massC << "(size: " << massC.N() << " x " << massC.M() << ')' << endl << endl;
    // Оператор копирования
    massC = massA;
    cout << "2. Copy assignment:" << endl;
    cout << "Matrix A:\n" << massA << "(size: " << massA.N() << " x " << massA.M() << ')' << endl;
    cout << "Matrix C:\n" << massC << "(size: " << massC.N() << " x " << massC.M() << ')' << endl << endl;
    // Конструктор перемещения
    SimpleMatrix massD(std::move(massB));
    cout << "3. Move constructor:" << endl;
    cout << "Matrix B:\n" << massB << "(size: " << massB.N() << " x " << massB.M() << ')' << endl;
    cout << "Matrix D:\n" << massD << "(size: " << massD.N() << " x " << massD.M() << ')' << endl << endl;
    // Оператор перемещения
    massD = std::move(massA);
    cout << "4. Move assignment:" << endl;;
    cout << "Matrix A:\n" << massA << "(size: " << massA.N() << " x " << massA.M() << ')' << endl;
    cout << "Matrix D:\n" << massD << "(size: " << massD.N() << " x " << massD.M() << ')' << endl << endl;
    // Очистка матриц
    cout << "Matrix C (size before clear): " << massC.N() << " x " << massC.M() << endl << endl;
    massC.clear();
    cout << "Matrix C (size after clear): " << massC.N() << " x " << massC.M() << endl << endl;
    // Умножение и деление матрицы на число
    massC = ( massD * 5 ) / 4;
    cout << "New Matrix C:\n" << massC << "(size: " << massC.N() << " x " << massC.M() << ')' << endl;
    cout << "New Matrix D:\n" << massD << "(size: " << massD.N() << " x " << massD.M() << ')' << endl << endl;
    // Сложение и вычитание матриц
    cout << "Matrix C + Matrix D:\n" << ( massC + massD ) << "(size: " << massC.N() << " x " << massC.M() << ')'
         << endl;
    cout << "Matrix C - Matrix D:\n" << ( massC - massD ) << "(size: " << massC.N() << " x " << massC.M() << ')' << endl
         << endl;
    // Транспонирование матрицы
    cout << "Matrix D (before transpose):\n" << massD << "(size: " << massD.N() << " x " << massD.M() << ')' << endl;
    massD = massD.transpose();
    cout << "Matrix D (after transpose):\n" << massD << "(size: " << massD.N() << " x " << massD.M() << ')' << endl
         << endl;
    massD = massD.transpose();
    // Умножение матриц
    SimpleMatrix temp = massD * massD.transpose();
    cout << "Matrix D * (Matrix D transpose):\n" << temp << "(size: " << temp.N() << " x " << temp.M() << ')' << endl
         << endl;
    // Сумма элементов строки
    cout << "Sum string(0): " << temp.sumString(0) << endl;
    cout << "Sum string(1): " << temp.sumString(1) << endl;
    // Сумма элементов столбца
    cout << "Sum column(0): " << temp.sumColumn(0) << endl;
    cout << "Sum column(1): " << temp.sumColumn(1) << endl << endl;
    // Применение различных функций к каждому элементу матрицы
    cout << "Matrix E:\n" << temp << endl;
    cout << "sqrt(for each elem in Matrix E):\n" << temp.doForEach(sqrt) << endl;
    cout << "sin(for each elem in Matrix E):\n" << temp.doForEach(sin) << endl;
    cout << "cos(for each elem in Matrix E):\n" << temp.doForEach(cos) << endl;
}