From 6080afee77ffcf81702bfc759437d80f36668692 Mon Sep 17 00:00:00 2001 From: "Jeremy W. Murphy" Date: Sun, 1 Nov 2015 03:28:59 +1100 Subject: [PATCH] Fix quotient_remainder to use the correct ordering of coefficients. Add equality operator and zero_element() for multiplication. --- include/boost/math/tools/polynomial.hpp | 73 ++++++++++++++++--------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/include/boost/math/tools/polynomial.hpp b/include/boost/math/tools/polynomial.hpp index afe3f0a8a..25c89fb7a 100644 --- a/include/boost/math/tools/polynomial.hpp +++ b/include/boost/math/tools/polynomial.hpp @@ -11,6 +11,7 @@ #endif #include +#include #include #include #include @@ -109,37 +110,51 @@ template std::pair< polynomial, polynomial > unchecked_synthetic_division(const polynomial& dividend, const polynomial& divisor) { - BOOST_ASSERT(dividend.degree() >= divisor.degree()); - BOOST_ASSERT(divisor.degree() != 0 || divisor[0] != T(0)); + BOOST_ASSERT(divisor.degree() <= dividend.degree()); std::vector intermediate_result(dividend.data()); + if (divisor.degree() == T(0)) + intermediate_result.insert(begin(intermediate_result), T(0)); { - T const normalizer = divisor[0]; - for (std::size_t i = 0; i < dividend.degree() - divisor.degree() + 1; i++) + typedef BOOST_DEDUCED_TYPENAME std::vector::reverse_iterator reverse_iterator; + T const normalizer = divisor[divisor.size() - 1]; + for (reverse_iterator i = intermediate_result.rbegin(); + i != intermediate_result.rbegin() + dividend.degree() - divisor.degree() + 1; + i++) { - if (intermediate_result[i] != T(0)) + if (*i != T(0)) { - T const coefficient = intermediate_result[i] /= normalizer; + T const coefficient = *i /= normalizer; for (std::size_t j = 1; j < divisor.degree() + 1; j++) - { - intermediate_result[i + j] += -divisor[j] * coefficient; - } + *(i + j) += -*(divisor.data().rbegin() + j) * coefficient; } } } { typedef BOOST_DEDUCED_TYPENAME std::vector::iterator iterator; - iterator const f = intermediate_result.begin(); - iterator const m = f + dividend.degree() - divisor.degree() + 1; - iterator const l = m + (*m == T(0) ? 1 : divisor.degree()); + iterator const f = intermediate_result.begin(); // remainder + iterator const m = f + std::max(divisor.degree(), 1ul); // quotient + iterator const l = intermediate_result.end(); BOOST_ASSERT(m - f > 0); BOOST_ASSERT(l - m > 0); - return std::make_pair(polynomial(f, m), polynomial(m, l)); + polynomial const quotient(m, l); + polynomial const remainder = *f != T(0) ? polynomial(f, m) : polynomial(); + return std::make_pair(quotient, remainder); } } + +/** + * Returns the zero element for multiplication of polynomials. + */ +template +polynomial zero_element(std::multiplies< polynomial >) +{ + return polynomial(); +} + /* Calculates a / b and a % b, returning the pair (quotient, remainder) together * because the same amount of computation yields both. */ @@ -147,22 +162,20 @@ template std::pair< polynomial, polynomial > quotient_remainder(const polynomial& dividend, const polynomial& divisor) { - if (divisor.degree() == 0 && divisor[0] == T(0)) + polynomial const zero = zero_element(std::multiplies< polynomial >()); + if (divisor == zero) throw std::domain_error("Divide by zero."); - if (dividend.degree() < divisor.degree()) - { - return std::make_pair(polynomial(T(0)), dividend); - } - + return std::make_pair(zero, dividend); // TODO: Is this right? return unchecked_synthetic_division(dividend, divisor); } template class polynomial : - dividable< polynomial - , modable< polynomial > > + equality_comparable< polynomial, + dividable< polynomial, + modable< polynomial > > > { public: // typedefs: @@ -178,6 +191,12 @@ public: { } + template + polynomial(I first, I last) + : m_data(first, last) + { + } + template polynomial(const U& point) { @@ -197,12 +216,6 @@ public: } } - template - polynomial(I first, I last) - : m_data(first, last) - { - } - // access: size_type size()const { return m_data.size(); } size_type degree()const { return m_data.size() - 1; } @@ -390,6 +403,12 @@ inline polynomial operator * (const U& a, const polynomial& b) return result; } +template +bool operator == (const polynomial &x, const polynomial &y) +{ + return x.data() == y.data(); +} + template inline std::basic_ostream& operator << (std::basic_ostream& os, const polynomial& poly) {