// // Created by trotfunky on 09/05/19. // #ifndef SNIPPETS_POLYNOMIAL_TPP #define SNIPPETS_POLYNOMIAL_TPP #include #include #include #include template class Polynomial; /** * Class allowing creation, manipulation and calculation of polynomials * Factors are stored from the lowest power to the highest * The polynomial has at least one factor, which defaults to zero * @tparam T Has to be an arithmetic type (std::is_arithmetic::value is true) */ template class Polynomial { public: Polynomial(); explicit Polynomial(const std::vector&); explicit Polynomial(const std::map&); template explicit Polynomial(const Polynomial&); int getDegree() const; Polynomial getNthDerivative(int n) const; template bool equals(const Polynomial&) const; template auto add(const Polynomial& operand) const -> Polynomial; template friend std::ostream& operator<<(std::ostream&, const Polynomial&); template T1 operator()(const T1&) const; T operator[](int) const; private: std::vector factors; double factorial(unsigned int n) const; template friend class Polynomial; }; //////////////////// /// /// /// Definitions /// /// /// //////////////////// template Polynomial::Polynomial() { // Not bad, but could be better with C++20. Not that useful either static_assert(std::is_arithmetic::value,"Polynomial must be of an arithmetic type!"); factors = {0}; } template Polynomial::Polynomial(const std::vector& polynomialFactors) : Polynomial() { if(polynomialFactors.size()>0) { factors = polynomialFactors; } } template Polynomial::Polynomial(const std::map& polynomialFactors) : Polynomial() { int degree = polynomialFactors.rbegin()->first; if(degree >= 0) { factors.pop_back(); } factors.reserve(degree); for(int i = 0;i<=degree;i++) { auto nextFactor = polynomialFactors.find(i); if(nextFactor != polynomialFactors.end()) { factors.push_back(nextFactor->second); } else { factors.push_back(0); } } } template template Polynomial::Polynomial(const Polynomial& copied) { static_assert(std::is_arithmetic::value,"Polynomial must be of an arithmetic type!"); for(const T1& factor : copied.factors) { factors.push_back(static_cast(factor)); } } /** * Returns the degree of the polynomial. * @tparam T Type of the polynomial factors * @return Degree of the polynomial, -1 if it is the null-polynomial */ template int Polynomial::getDegree() const { for(int i = factors.size()-1;i>=0;i--) { if(factors[i] != 0) { return(i); } } return(-1); } /** * Computes the nth derivative of the polynomial * @tparam T Polyniaml factor type * @param n Order of the derivative * @return Derived polynomial, null-polynomial if the order is greater than the degree */ template Polynomial Polynomial::getNthDerivative(int n) const { if(n<=0) { return(Polynomial(*this)); } if(n>getDegree()) { return(Polynomial()); } std::vector newFactors; for(int i = n;i(newFactors)); } template double Polynomial::factorial(unsigned int n) const { double value = 1; for(unsigned int i = 2;i<=n;i++) { value *= i; } return(value); } template template bool Polynomial::equals(const Polynomial& operand) const { if(getDegree() != operand.getDegree()) { return(false); } if(getDegree() == -1) { return(true); } const std::vector& p2Factors = operand.factors; for(int i = factors.size();i>=0;i--) { if(factors[i] != p2Factors[i]) { return(false); } } return(true); } template template auto Polynomial::add(const Polynomial& operand) const -> Polynomial { bool isLargest = true; int largestSize = factors.size(); int smallestSize = operand.factors.size(); if(getDegree() < operand.getDegree()) { isLargest = false; smallestSize = factors.size(); largestSize = operand.factors.size(); } std::vector resultPolynomial = {}; resultPolynomial.reserve(largestSize); for(int i = 0;i(resultPolynomial); } //////////////////// /// /// /// Operators /// /// /// //////////////////// template bool operator==(const Polynomial& p1, const Polynomial& p2) { return(p1.equals(p2)); } /** * Computes the sum of the two polynomials by adding factor by factor at first and pushing back * the leftover factors from the largest polynomial if their are different in degree. * @tparam T Type of the first polynomial * @tparam R Type of the second polynomial * @param p1 First polynomial * @param p2 Second polynomial * @return Sum of the two polynomials, null polynomial if both of them are null. The type is deduced from the addition * of the first factors of the two polynomials. */ template auto operator+(const Polynomial& p1, const Polynomial& p2) -> Polynomial { return(p1.add(p2)); } template std::ostream& operator<<(std::ostream& ostream, const Polynomial& polynomial) { if(polynomial.getDegree() < 0) { ostream << "0 "; return ostream; } const std::vector& factors = polynomial.factors; if(factors[0] > 0) { ostream << factors[0] << " "; } else if(factors[0] < 0) { ostream << std::showpos << factors[0] << " "; } for(int i = 1;i template T1 Polynomial::operator()(const T1& input) const { static_assert(std::is_arithmetic::value,"Cannot evaluate polynomial at a non arithmetic value !"); if(getDegree() == -1) { return(0); } T1 returnValue = 0; for(int i = 0;i T Polynomial::operator[](const int index) const { return(factors.at(index)); } #endif //SNIPPETS_POLYNOMIAL_TPP