diff --git a/doc/internals/polynomial.qbk b/doc/internals/polynomial.qbk index 9f11796940..81709c2efb 100644 --- a/doc/internals/polynomial.qbk +++ b/doc/internals/polynomial.qbk @@ -34,6 +34,10 @@ const value_type& operator[](size_type i)const; std::vector const& data() const; std::vector& data(); + operator bool() const; + + // modify: + void set_zero(); // operators: template diff --git a/example/polynomial_arithmetic.cpp b/example/polynomial_arithmetic.cpp index 70dc91b1f1..78efd06d0d 100644 --- a/example/polynomial_arithmetic.cpp +++ b/example/polynomial_arithmetic.cpp @@ -197,6 +197,17 @@ even otherwise. That is: //] [/polynomial_arithmetic_5] + //[polynomial_arithmetic_6] + /* For performance and convenience, we can test whether a polynomial is zero + * by implicitly converting to bool with the same semantics as int. */ + polynomial zero; // Default construction is 0. + cout << "zero: " << (zero ? "not zero" : "zero") << "\n"; + cout << "r: " << (r ? "not zero" : "zero") << "\n"; + /* We can also set a polynomial to zero without needing a another zero + * polynomial to assign to it. */ + r.set_zero(); + cout << "r: " << (r ? "not zero" : "zero") << "\n"; + //] [/polynomial_arithmetic_6] } catch (exception const &e) { diff --git a/include/boost/math/tools/polynomial.hpp b/include/boost/math/tools/polynomial.hpp index ae62e8aea7..df1bde3746 100644 --- a/include/boost/math/tools/polynomial.hpp +++ b/include/boost/math/tools/polynomial.hpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -192,8 +193,8 @@ std::pair< polynomial, polynomial > division(polynomial u, const polynomial& v) { BOOST_ASSERT(v.size() <= u.size()); - BOOST_ASSERT(v != zero_element(std::multiplies< polynomial >())); - BOOST_ASSERT(u != zero_element(std::multiplies< polynomial >())); + BOOST_ASSERT(v); + BOOST_ASSERT(u); typedef typename polynomial::size_type N; @@ -246,9 +247,9 @@ template std::pair< polynomial, polynomial > quotient_remainder(const polynomial& dividend, const polynomial& divisor) { - BOOST_ASSERT(divisor != zero_element(std::multiplies< polynomial >())); + BOOST_ASSERT(divisor); if (dividend.size() < divisor.size()) - return std::make_pair(zero_element(std::multiplies< polynomial >()), dividend); + return std::make_pair(polynomial(), dividend); return detail::division(dividend, divisor); } @@ -390,7 +391,7 @@ class polynomial : polynomial& operator %=(const U& /*value*/) { // We can always divide by a scalar, so there is no remainder: - *this = zero_element(std::multiplies()); + this->set_zero(); return *this; } @@ -413,10 +414,9 @@ class polynomial : polynomial& operator *=(const polynomial& value) { // TODO: FIXME: use O(N log(N)) algorithm!!! - polynomial const zero = zero_element(std::multiplies()); - if (value == zero) + if (!value) { - *this = zero; + this->set_zero(); return *this; } std::vector prod(size() + value.size() - 1, T(0)); @@ -456,6 +456,33 @@ class polynomial : normalize(); return *this; } + + // Convenient and efficient query for zero. + bool is_zero() const + { + return m_data.empty(); + } + + // Conversion to bool. +#ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS + typedef bool (polynomial::*unmentionable_type)() const; + + BOOST_FORCEINLINE operator unmentionable_type() const + { + return is_zero() ? false : &polynomial::is_zero; + } +#else + BOOST_FORCEINLINE explicit operator bool() const + { + return !m_data.empty(); + } +#endif + + // Fast way to set a polynomial to zero. + void set_zero() + { + m_data.clear(); + } /** Remove zero coefficients 'from the top', that is for which there are no * non-zero coefficients of higher degree. */ diff --git a/test/test_polynomial.cpp b/test/test_polynomial.cpp index 65498d21cd..0ce45354a6 100644 --- a/test/test_polynomial.cpp +++ b/test/test_polynomial.cpp @@ -299,6 +299,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_odd_even, T, all_test_types) BOOST_CHECK_EQUAL(even(b), true); } + BOOST_AUTO_TEST_CASE_TEMPLATE( test_pow, T, all_test_types ) { polynomial a(d3a.begin(), d3a.end()); @@ -321,3 +322,23 @@ BOOST_AUTO_TEST_CASE_TEMPLATE( test_pow, T, all_test_types ) BOOST_CHECK_THROW(pow(a, -1), std::domain_error); BOOST_CHECK_EQUAL(pow(one, 137), one); } + + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_bool, T, all_test_types) +{ + polynomial const zero; + polynomial const a(d0a.begin(), d0a.end()); + BOOST_CHECK_EQUAL(bool(zero), false); + BOOST_CHECK_EQUAL(bool(a), true); +} + + +BOOST_AUTO_TEST_CASE_TEMPLATE(test_set_zero, T, all_test_types) +{ + polynomial const zero; + polynomial a(d0a.begin(), d0a.end()); + a.set_zero(); + BOOST_CHECK_EQUAL(a, zero); + a.set_zero(); // Ensure that setting zero to zero is a no-op. + BOOST_CHECK_EQUAL(a, zero); +}