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

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

class Polynom {
 private:

    // Число степеней (отсчет с 0)
    size_t n_;
    // Указатель на массив с коэффициентами
    double *factors_ = nullptr;

 protected:

    // Метод, возвращающий полином без хвоста (убирает последние члены равные 0: 0*x^21 + 0*x^22 + ... + 0*x^k)
    Polynom simplify() const {
        size_t i = 0;
        if (n_ > 0) {
            for (i = this->n_ - 1; i > 0; --i) { // Идем от конца к началу
                if (this->factors_[i] != 0) { // Если встречен первый элемент != 0, то это конец полинома
                    break;
                }
            }
            return Polynom(*this, i + 1);
        }
        return *this;
    }

 public:

    // Конструктор
    explicit Polynom(size_t n) : n_(n) {
        if (n > 0) {
            factors_ = new double[n] {0};
        }
    }

    // Конструкторы копирования
    Polynom(const Polynom &arg) : Polynom(arg.n_) {
        n_ = arg.n_;
        std::copy(arg.factors_, arg.factors_ + arg.n_, this->factors_); // Копируем коэф. из arg в this
    }
    Polynom(const Polynom &arg, size_t N) : Polynom(N) { // N - явное задание количества коэф.
        n_ = N;
        std::copy(arg.factors_, arg.factors_ + N, this->factors_); // Копируем коэф. из arg в this
    }

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

    // Конструктор перемещения
    Polynom(Polynom &&arg) noexcept {
        n_ = arg.n_, factors_ = arg.factors_;
        arg.n_ = 0, arg.factors_ = nullptr;
    }

    // Оператор перемещения
    Polynom &operator=(Polynom &&arg) noexcept {
        if (this != &arg) {
            swap(*this, arg); // Меняем местами this и arg
            delete[] arg.factors_, arg.factors_ = nullptr; // Освобождаем прежнюю память this (которая в arg)
            arg.n_ = 0; // Количество элементов в 0
        }
        return *this;
    }

    // Деструктор
    virtual ~Polynom() { delete[] factors_; }

    // Стандартные операторы
    //
    // Получение коэффициента полинома по индексу
    double &operator[](size_t k) {
        return factors_[k];
    }

    // Вычисление значения полинома по X
    double operator()(const double &x) const {
        double s = 0, q = 1;
        for (size_t i = 0; i < n_; ++i) {
            s += this->factors_[i] * q;
            q *= x;
        }
        return s;
    }

    // Операции с полиномами
    //
    // Сложение полиномов
    Polynom operator+(const Polynom &arg) const {
        size_t mx = std::max(this->n_, arg.n_), mn = std::min(this->n_, arg.n_);
        Polynom result(mx); // Размер максимального из this и arg
        for (size_t i = 0; i < mn; ++i) { // Идем до минимального из this и arg
            result[i] = this->factors_[i] + arg.factors_[i];
        }
        if (arg.n_ > this->n_) { // Если один из полиномов больше (arg), то копируем данные в result из arg
            std::copy(arg.factors_ + mn, arg.factors_ + mx, result.factors_ + mn);
        } else { // иначе копируем данные из this
            std::copy(factors_ + mn, factors_ + mx, result.factors_ + mn);
        }
        return result.simplify(); // Возврат упрощенного полинома
    }

    // Смена знака коэффициентов полинома
    Polynom operator-() const {
        Polynom result(n_);
        for (size_t i = 0; i < n_; ++i) {
            result[i] = -factors_[i];
        }
        return result;
    }

    // Вычитание полиномов
    Polynom operator-(const Polynom &arg) const {
        return ( *this + ( -arg ) );
    }

    // Умножение полиномов
    Polynom operator*(const Polynom &arg) const {
        size_t mx = std::max(this->n_, arg.n_), mn = std::min(this->n_, arg.n_), sz = mx + mn;
        Polynom result(sz);
        for (size_t i = 0; i < this->n_; ++i) {
            for (size_t j = 0; j < arg.n_; ++j) {
                result.factors_[i + j] += this->factors_[i] * arg.factors_[j];
            }
        }
        return result.simplify();
    }

    // Производная от полинома
    Polynom derivative() const {
        if (this->n_ > 1) {
            Polynom result(this->n_ - 1);
            for (size_t i = 1; i < this->n_; ++i) {
                result.factors_[i - 1] = this->factors_[i] * i;
            }
            return result.simplify();
        }
        return Polynom(1);
    }

    // Интеграл от полинома (C = const)
    Polynom integral(double C = 0) const {
        Polynom result(this->n_ + 1);
        result[0] = C;
        for (size_t i = 1; i < result.n_; ++i) {
            result.factors_[i] = this->factors_[i - 1] / i;
        }
        return result.simplify();
    }

    // Равны ли два полинома?
    bool operator==(const Polynom &arg) const {
        if (n_ != arg.n_) {
            return false;
        }
        for (size_t i = 0; i < arg.n_; ++i) {
            if (this->factors_[i] != arg.factors_[i]) {
                return false;
            }
        }
        return true;
    }

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

    // Операции с числами
    //
    // Сложение полинома с числом
    Polynom operator+(const double &d) const {
        Polynom result(*this);
        result.factors_[0] += d;
        return result;
    }

    // Вычитание числа из полинома
    Polynom operator-(const double &d) const {
        return ( *this + ( -d ) );
    }

    // Умножение полинома на число
    Polynom operator*(const double &d) const {
        Polynom result(*this);
        for (size_t i = 0; i < n_; ++i) {
            result.factors_[i] *= d;
        }
        return ( d != 0 ? result : result.simplify() ); // Если d = 0, то упрощаем полином
    }

    // Деление полинома на число
    Polynom operator/(const double &d) const {
        return ( *this * ( 1. / d ) );
    }

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

    // Дружественные функции и операторы
    //
    // Дружественный оператор вывода полинома в выходной поток os (cout, ...)
    friend std::ostream &operator<<(std::ostream &os, const Polynom &p) {
        if (p.n_ > 0) {
            os << p.factors_[0];
            for (size_t i = 1; i < p.n_; ++i) {
                os << ' ' << ( p.factors_[i] >= 0 ? '+' : '-' ) << ' ' << fabs(p.factors_[i]) << "*x^" << i;
            }
        }
        return os;
    }

    friend void swap(Polynom &first, Polynom &second) noexcept {
        std::swap(first.factors_, second.factors_);
        std::swap(first.n_, second.n_);
    }
};

int main() {
    // Полиномы 9-той степени и 11-той степени
    const size_t N1 = 10, N2 = 12;
    Polynom a(N1), b(N2);
    for (size_t i = 0; i < N1; ++i) { a[i] = rand() % 100; }
    for (size_t i = 0; i < N2; ++i) { b[i] = rand() % 100; }
    // Простейшие операции с полиномами
    cout << "A: " << a << endl;
    cout << "A(551.): " << a(551.) << endl; // значение полинома при x = 551
    cout << "B: " << b << endl;
    cout << "B(551.): " << b(551.) << endl; // значение полинома при x = 551
    cout << "A == B ? " << ( a == b ? "TRUE" : "FALSE" ) << endl;
    cout << "A != B ? " << ( a != b ? "TRUE" : "FALSE" ) << endl;
    cout << "A + B: " << a + b << endl;
    cout << "A - A: " << a - a << endl;
    cout << "A * 5: " << a * 5 << endl;
    cout << "A / 5: " << a / 5 << endl << endl;
    // Конструктор копирования (производная от полинома)
    Polynom derivA(a.derivative());
    cout << "A': " << derivA << endl;
    // Оператор копирования (производная от полинома)
    Polynom derivB = b.derivative();
    cout << "B': " << derivB << endl;
    // Конструктор перемещения (сумма производных двух полиномов)
    Polynom derivAB(std::move(a.derivative() + b.derivative()));
    cout << "A' + B': " << derivAB << endl;
    // Оператор перемещения (произведение производных двух полиномов)
    derivAB = std::move(a.derivative() * b.derivative());
    cout << "A' * B': " << derivAB << endl << endl;
    // Интегралы от полиномов
    cout << "[Integral] integral(A): " << a.integral() << endl;
    cout << "[Integral] integral(B): " << b.integral() << endl;
    cout << "[Integral] integral(A) * integral(B): " << a.integral() * b.integral() << endl;
    cout << "[Integral] integral(A * B): " << ( a * b ).integral() << endl;
}