From 2334a427b1e42abfa51fd02c6851d47cac7aee81 Mon Sep 17 00:00:00 2001 From: Anton Date: Sun, 20 Oct 2024 05:14:29 +0300 Subject: [PATCH] added constructor from string, added documentation --- Readme.md | 74 ++++++++ src/polynom.hpp | 441 +++++++++++++++++++++++++++++-------------- tests/test_basic.cpp | 8 +- 3 files changed, 379 insertions(+), 144 deletions(-) create mode 100644 Readme.md diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..ec89a18 --- /dev/null +++ b/Readme.md @@ -0,0 +1,74 @@ +# Библиотека polynom.hpp + +## Описание +Данная библиотека предоставляет пользователю класс Polynom, объявленный в файле polygon.hpp, который умеет работать с многочленами от нескольких переменных, выполнять над ними математические операции, а также вычислять значение, подставляя значения в переменные. + +Коэфициентами при членах, а также подставляемые значения могут быть представлены любыми типами, как стандартными, так и пользовательскими. На пользовательские коэфициенты и подставляемые значения накладываются некоторые ограничения, но об этом позднее. + +Степени при переменных это беззнаковые целые числа. + +## Использование + +### Инициализация + +Polynom представляет из себя шаблонный класс, где шаблонным типом является коэфициент при членах, который нужно указать при инициализации многочлена. +```cpp +Polygon p; +``` +Конструктор по умолчанию создаст нулевой многочлен. + +Задать многочлен можно также и через строку. Строка должна состоять из членов, разделенных знаками + и -. Каждый член имеет вид [коэфициент]буква^степень*буква^степень... Допускается использование одной буквы более одного раза, а также переменной в первой степени, после которой можно не писать ^1, а также не писать символ *. + +Здесь есть тонкость. Так как класс может не знать как создать например пользовательский коэфициент из строки, а также как он выглядит здесь накладываются два ограничения. + +1) Вместе со строкой в конструктор передаётся и функция, принимающая на вход std::string, с возвращаемым типом коэфициента. Для базовых типов уже заготовлены функции, находящиеся в пространстве имён pconverter +2) Так как класс не знает, как выглядит коэфициент, ему нужно как то указать на его границы. Именно поэтому все коэфициенты необходимо оборачивать в квадратные скобки, даже если это свободный член. + +Пример инициализации многочлена из строки: +```cpp +Polygon p("[5]x^2*y-[2]xyx-[6]", pconverter::to_int); +``` + +Также константный многочлен можно задать, как +```cpp +Polygon p(10.5); +``` + +Внутри класса многочлен представлен, как +```cpp +std::map, T> +``` +Предусмотрена возможность задания многочлена через данную структуру данных + +### Арифмитеческие операции + +Над многочленом можно проводить различные арифмитические операции, а именно + +1) Сложение +2) Вычитание +3) Умножение +4) Возведение в целую неотрицательную +5) Унарный минус +6) Прибавление и вычитание константы +7) Умножение на константу +8) Унарный минус + +### Исполнение + +Класс Polynom содержит метод apply, который подставляет в буквы значение и возвращает результат. Его сигнатура выглядит следующим образом: +```cpp +template +U apply(std::map m) const; +``` + +Применение выглядит, как: +```cpp +int ans = p1.apply(std::map{ + {'x', 2}, + {'y', 3} + }); +``` + +### Ограничения + +Коэфициенты и подставляемые значения должны представлять собой линейное пространство. В частности, конструктор по умолчанию от типа коэфициента должен возвращать "ноль", а конструктор вида T(1) от типа подставляемого значения должен возвращать "единицу". \ No newline at end of file diff --git a/src/polynom.hpp b/src/polynom.hpp index 6a8ab25..8aa55b9 100644 --- a/src/polynom.hpp +++ b/src/polynom.hpp @@ -1,15 +1,15 @@ #pragma once +#include #include #include +#include #include #include -#include -#include -template -class Polynom { -public: +template class Polynom +{ + public: Polynom(T val = T()); Polynom(Polynom &other); Polynom(Polynom &&other); @@ -19,126 +19,225 @@ class Polynom { Polynom(std::map, T> otherCoef); - Polynom(std::string_view str); - Polynom(const char *str); + Polynom(std::string_view str, T (*transform)(const std::string &)); + Polynom(const char *str, T (*transform)(const std::string &)); - template - U apply(std::map m) const; + template U apply(std::map m) const; - template - friend Polynom operator+(const Polynom &lhs, const Polynom &rhs); + template friend Polynom operator+(const Polynom &lhs, const Polynom &rhs); - template - friend Polynom operator-(const Polynom &lhs, const Polynom &rhs); + template friend Polynom operator-(const Polynom &lhs, const Polynom &rhs); - template - friend Polynom operator*(const Polynom &lhs, const Polynom &rhs); + template friend Polynom operator*(const Polynom &lhs, const Polynom &rhs); Polynom &operator+=(const Polynom &other); Polynom &operator-=(const Polynom &other); Polynom &operator*=(const Polynom &other); - template - friend Polynom operator*(const Polynom &lhs, const U &rhs); + template friend Polynom operator*(const Polynom &lhs, const U &rhs); - template - friend Polynom operator*(const U &lhs, const Polynom &rhs); + template friend Polynom operator*(const U &lhs, const Polynom &rhs); Polynom &operator*=(const T &other); - template - friend Polynom operator+(const Polynom &lhs, const U &rhs); + template friend Polynom operator+(const Polynom &lhs, const U &rhs); - template - friend Polynom operator+(const U &lhs, const Polynom &rhs); + template friend Polynom operator+(const U &lhs, const Polynom &rhs); Polynom &operator+=(const T &other); - template - friend Polynom operator-(const Polynom &lhs, const U &rhs); + template friend Polynom operator-(const Polynom &lhs, const U &rhs); - template - friend Polynom operator-(const U &lhs, const Polynom &rhs); + template friend Polynom operator-(const U &lhs, const Polynom &rhs); Polynom &operator-=(const T &other); Polynom operator-() const; - template - friend Polynom operator^(const Polynom lhs, const unsigned long long rhs); + template friend Polynom operator^(const Polynom lhs, const unsigned long long rhs); Polynom &operator^=(const unsigned long long n); -private: + private: void clean(); - std::map, T> coef; + std::map, T> coef; }; -template -Polynom::Polynom(T val) { - if (val != T()) { +namespace +{ +template T power(T base, unsigned long long exp) +{ + T ret = (T)1; + for (unsigned long long i = 0; i < exp; ++i) + { + ret *= base; + } + return ret; +} +} + +template Polynom::Polynom(T val) +{ + if (val != T()) + { coef[{}] = val; } clean(); } -template -Polynom::Polynom(Polynom &other) : coef(other.coef) {} +template Polynom::Polynom(Polynom &other) : coef(other.coef) +{ +} -template -Polynom::Polynom(Polynom &&other) : coef(std::move(other.coef)) {} +template Polynom::Polynom(Polynom &&other) : coef(std::move(other.coef)) +{ +} -template -Polynom &Polynom::operator=(Polynom &other) { - if (this != &other) { +template Polynom &Polynom::operator=(Polynom &other) +{ + if (this != &other) + { coef = other.coef; } return *this; } -template -Polynom &Polynom::operator=(Polynom &&other) { - if (this != &other) { +template Polynom &Polynom::operator=(Polynom &&other) +{ + if (this != &other) + { coef = std::move(other.coef); } return *this; } -template -Polynom::Polynom(std::map, T> otherCoef) : coef(otherCoef) {} - -template -Polynom::Polynom(std::string_view str) { - // TODO: Implement this +template Polynom::Polynom(std::map, T> otherCoef) : coef(otherCoef) +{ } -template -Polynom::Polynom(const char *str) : Polynom(std::string_view(str)) {} +template Polynom::Polynom(std::string_view str, T (*transform)(const std::string &)) +{ + try + { + coef.clear(); + bool positive = true; + std::string buf; + int pos = 0; + while (pos != str.size()) + { + std::string buf; + while (pos != str.size() && str[pos] != '+' && str[pos] != '-') + { + buf += str[pos]; + ++pos; + } -template -T power(T base, unsigned long long exp) { - if (exp == 1) { - return base; - } - else { - T temp = power(base, exp/2); - if (exp % 2 == 0) { - return temp * temp; - } - else { - return base * temp * temp; + T curCoef; + std::map power; + if (buf.size() > 0 && buf[0] == '[') + { + std::string strCoef; + int posC = 1; + while (buf[posC] != ']') + { + strCoef += buf[posC]; + ++posC; + } + T (*func)(const std::string &) = nullptr; + try + { + func = reinterpret_cast(transform); + } + catch (const std::exception &e) + { + throw std::invalid_argument("Invalid transform function"); + } + try + { + curCoef = func(strCoef); + } + catch (const std::exception &e) + { + throw std::invalid_argument("Cannot transform argument"); + } + buf = buf.substr(posC + 1, buf.size() - posC - 1); + } + else + { + curCoef = 1; + } + if (!positive) + curCoef = -curCoef; + + int posV = 0; + while (posV != buf.size()) + { + char c = buf[posV]; + if (posV + 1 == buf.size() || buf[posV + 1] != '^') + { + if (power.find(c) == power.end()) + power[c] = 1; + else + power[c] += 1; + ++posV; + if (buf[posV] == '*') + ++posV; + } + else + { + ++posV; + ++posV; + std::string p; + while (posV != buf.size() && buf[posV] != '*') + { + p += buf[posV]; + ++posV; + } + if (power.find(c) == power.end()) + power[c] = stoul(p); + else + power[c] += stoul(p); + if (posV != buf.size() && buf[posV] == '*') + ++posV; + } + } + + if (coef.find(power) == coef.end()) + coef[power] = curCoef; + else + coef[power] += curCoef; + + if (pos != str.size()) + { + if (str[pos]) + positive = true; + else + positive = false; + ++pos; + } } } + catch (const std::exception &e) + { + throw std::invalid_argument("Couldn't parse string"); + } } template -template -U Polynom::apply(std::map m) const { +Polynom::Polynom(const char *str, T (*transform)(const std::string &)) : Polynom(std::string_view(str), transform) +{ +} + +template template U Polynom::apply(std::map m) const +{ U result = U(); - for (auto it = coef.begin(); it != coef.end(); ++it) { + for (auto it = coef.begin(); it != coef.end(); ++it) + { U term = 1; - for (auto jt = it->first.begin(); jt != it->first.end(); ++jt) { - if (m.find(jt->first) == m.end()) { + for (auto jt = it->first.begin(); jt != it->first.end(); ++jt) + { + if (m.find(jt->first) == m.end()) + { throw std::invalid_argument("Variable not found in map"); } term *= power(m[jt->first], jt->second); @@ -149,29 +248,33 @@ U Polynom::apply(std::map m) const { return result; } -template -Polynom operator+(const Polynom &lhs, const Polynom &rhs) { - lhs+=rhs; +template Polynom operator+(const Polynom &lhs, const Polynom &rhs) +{ + lhs += rhs; return lhs; } -template -Polynom operator-(const Polynom &lhs, const Polynom &rhs) { - lhs-=rhs; +template Polynom operator-(const Polynom &lhs, const Polynom &rhs) +{ + lhs -= rhs; } -template -Polynom operator*(const Polynom &lhs, const Polynom &rhs) { - lhs*=rhs; +template Polynom operator*(const Polynom &lhs, const Polynom &rhs) +{ + lhs *= rhs; return lhs; } -template -Polynom &Polynom::operator+=(const Polynom &other) { - for (auto it = other.coef.begin(); it != other.coef.end(); ++it) { - if (coef.find(it->first) == coef.end()) { +template Polynom &Polynom::operator+=(const Polynom &other) +{ + for (auto it = other.coef.begin(); it != other.coef.end(); ++it) + { + if (coef.find(it->first) == coef.end()) + { coef[it->first] = it->second; - } else { + } + else + { coef[it->first] += it->second; } } @@ -179,12 +282,16 @@ Polynom &Polynom::operator+=(const Polynom &other) { return *this; } -template -Polynom &Polynom::operator-=(const Polynom &other) { - for (auto it = other.coef.begin(); it != other.coef.end(); ++it) { - if (coef.find(it->first) == coef.end()) { +template Polynom &Polynom::operator-=(const Polynom &other) +{ + for (auto it = other.coef.begin(); it != other.coef.end(); ++it) + { + if (coef.find(it->first) == coef.end()) + { coef[it->first] = -it->second; - } else { + } + else + { coef[it->first] -= it->second; } } @@ -192,22 +299,31 @@ Polynom &Polynom::operator-=(const Polynom &other) { return *this; } -template -Polynom &Polynom::operator*=(const Polynom &other) { +template Polynom &Polynom::operator*=(const Polynom &other) +{ std::map, T> temp; - for (auto it1 = coef.begin(); it1 != coef.end(); ++it1) { - for (auto it2 = other.coef.begin(); it2 != other.coef.end(); ++it2) { + for (auto it1 = coef.begin(); it1 != coef.end(); ++it1) + { + for (auto it2 = other.coef.begin(); it2 != other.coef.end(); ++it2) + { std::map new_key = it1->first; - for (auto jt = it2->first.begin(); jt != it2->first.end(); ++jt) { - if (new_key.find(jt->first) == new_key.end()) { + for (auto jt = it2->first.begin(); jt != it2->first.end(); ++jt) + { + if (new_key.find(jt->first) == new_key.end()) + { new_key[jt->first] = jt->second; - } else { + } + else + { new_key[jt->first] += jt->second; } } - if (temp.find(new_key) == temp.end()) { + if (temp.find(new_key) == temp.end()) + { temp[new_key] = it1->second * it2->second; - } else { + } + else + { temp[new_key] += it1->second * it2->second; } } @@ -217,96 +333,143 @@ Polynom &Polynom::operator*=(const Polynom &other) { return *this; } -template -Polynom operator*(const Polynom &lhs, const T &rhs) { - lhs*=rhs; +template Polynom operator*(const Polynom &lhs, const T &rhs) +{ + lhs *= rhs; return lhs; } -template -Polynom operator*(const T &lhs, const Polynom &rhs) { - rhs*=lhs; +template Polynom operator*(const T &lhs, const Polynom &rhs) +{ + rhs *= lhs; return rhs; } -template -Polynom &Polynom::operator*=(const T &other) { - for (auto it = coef.begin(); it != coef.end(); ++it) { +template Polynom &Polynom::operator*=(const T &other) +{ + for (auto it = coef.begin(); it != coef.end(); ++it) + { it->second *= other; } } -template -Polynom operator+(const Polynom &lhs, const T &rhs) { - lhs+=rhs; +template Polynom operator+(const Polynom &lhs, const T &rhs) +{ + lhs += rhs; return lhs; } -template -Polynom operator+(const T &lhs, const Polynom &rhs) { - rhs+=lhs; +template Polynom operator+(const T &lhs, const Polynom &rhs) +{ + rhs += lhs; return rhs; } -template -Polynom &Polynom::operator+=(const T &other) { - if (coef.find({}) == coef.end()) { +template Polynom &Polynom::operator+=(const T &other) +{ + if (coef.find({}) == coef.end()) + { coef[{}] = other; - } else { + } + else + { coef[{}] += other; } } -template -Polynom operator-(const Polynom &lhs, const T &rhs) { - lhs-=rhs; +template Polynom operator-(const Polynom &lhs, const T &rhs) +{ + lhs -= rhs; return lhs; } -template -Polynom operator-(const T &lhs, const Polynom &rhs) { - rhs-=lhs; +template Polynom operator-(const T &lhs, const Polynom &rhs) +{ + rhs -= lhs; return rhs; } -template -Polynom &Polynom::operator-=(const T &other) { - if (coef.find({}) == coef.end()) { +template Polynom &Polynom::operator-=(const T &other) +{ + if (coef.find({}) == coef.end()) + { coef[{}] = -other; - } else { + } + else + { coef[{}] -= other; } } -template -Polynom operator^(const Polynom lhs, const unsigned long long rhs) { - lhs^=rhs; +template Polynom operator^(const Polynom lhs, const unsigned long long rhs) +{ + lhs ^= rhs; return lhs; } -template -Polynom &Polynom::operator^=(const unsigned long long n) { +template Polynom &Polynom::operator^=(const unsigned long long n) +{ *this = power(*this, n); return *this; } -template -Polynom Polynom::operator-() const { +template Polynom Polynom::operator-() const +{ Polynom result = *this; - for (auto it = result.coef.begin(); it != result.coef.end(); ++it) { + for (auto it = result.coef.begin(); it != result.coef.end(); ++it) + { it->second = -it->second; } return result; } -template -void Polynom::clean() { - for (auto it = coef.begin(); it != coef.end();) { - if (it->second == T()) { +template void Polynom::clean() +{ + for (auto it = coef.begin(); it != coef.end();) + { + if (it->second == T()) + { coef.erase(it++); } - else { + else + { ++it; } } } + +namespace pconverter +{ +int to_int(const std::string &s) +{ + return std::stoi(s); +} +double to_double(const std::string &s) +{ + return std::stod(s); +} +float to_float(const std::string &s) +{ + return std::stof(s); +} +long to_long(const std::string &s) +{ + return std::stol(s); +} +long long to_long_long(const std::string &s) +{ + return std::stoll(s); +} +unsigned long to_unsigned_long(const std::string &s) +{ + return std::stoul(s); +} +unsigned long long to_unsigned_long_long(const std::string &s) +{ + return std::stoull(s); +} +char to_char(const std::string &s) +{ + return s[0]; +} +} \ No newline at end of file diff --git a/tests/test_basic.cpp b/tests/test_basic.cpp index 1907c46..d14a42b 100644 --- a/tests/test_basic.cpp +++ b/tests/test_basic.cpp @@ -2,16 +2,14 @@ #include #include +#include int main() { - std::map, int> m; - m[{{'x', 2}}] = 1; - m[{{'y', 1}}] = 2; - Polynom p1(m); + Polynom p1("x^2+[2]y+[5]", pconverter::to_int); int ans = p1.apply(std::map{ {'x', 2}, {'y', 3} }); - assert(ans == 10); + assert(ans == 15); return 0; } \ No newline at end of file