Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:46:34

0001 //  (C) Copyright John Maddock 2006.
0002 //  (C) Copyright Jeremy William Murphy 2015.
0003 
0004 
0005 //  Use, modification and distribution are subject to the
0006 //  Boost Software License, Version 1.0. (See accompanying file
0007 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0008 
0009 #ifndef BOOST_MATH_TOOLS_POLYNOMIAL_HPP
0010 #define BOOST_MATH_TOOLS_POLYNOMIAL_HPP
0011 
0012 #ifdef _MSC_VER
0013 #pragma once
0014 #endif
0015 
0016 #include <boost/math/tools/assert.hpp>
0017 #include <boost/math/tools/config.hpp>
0018 #include <boost/math/tools/cxx03_warn.hpp>
0019 #include <boost/math/tools/rational.hpp>
0020 #include <boost/math/tools/real_cast.hpp>
0021 #include <boost/math/policies/error_handling.hpp>
0022 #include <boost/math/special_functions/binomial.hpp>
0023 #include <boost/math/tools/detail/is_const_iterable.hpp>
0024 
0025 #include <vector>
0026 #include <ostream>
0027 #include <algorithm>
0028 #include <initializer_list>
0029 #include <type_traits>
0030 #include <iterator>
0031 
0032 namespace boost{ namespace math{ namespace tools{
0033 
0034 template <class T>
0035 T chebyshev_coefficient(unsigned n, unsigned m)
0036 {
0037    BOOST_MATH_STD_USING
0038    if(m > n)
0039       return 0;
0040    if((n & 1) != (m & 1))
0041       return 0;
0042    if(n == 0)
0043       return 1;
0044    T result = T(n) / 2;
0045    unsigned r = n - m;
0046    r /= 2;
0047 
0048    BOOST_MATH_ASSERT(n - 2 * r == m);
0049 
0050    if(r & 1)
0051       result = -result;
0052    result /= n - r;
0053    result *= boost::math::binomial_coefficient<T>(n - r, r);
0054    result *= ldexp(1.0f, m);
0055    return result;
0056 }
0057 
0058 template <class Seq>
0059 Seq polynomial_to_chebyshev(const Seq& s)
0060 {
0061    // Converts a Polynomial into Chebyshev form:
0062    typedef typename Seq::value_type value_type;
0063    typedef typename Seq::difference_type difference_type;
0064    Seq result(s);
0065    difference_type order = s.size() - 1;
0066    difference_type even_order = order & 1 ? order - 1 : order;
0067    difference_type odd_order = order & 1 ? order : order - 1;
0068 
0069    for(difference_type i = even_order; i >= 0; i -= 2)
0070    {
0071       value_type val = s[i];
0072       for(difference_type k = even_order; k > i; k -= 2)
0073       {
0074          val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
0075       }
0076       val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
0077       result[i] = val;
0078    }
0079    result[0] *= 2;
0080 
0081    for(difference_type i = odd_order; i >= 0; i -= 2)
0082    {
0083       value_type val = s[i];
0084       for(difference_type k = odd_order; k > i; k -= 2)
0085       {
0086          val -= result[k] * chebyshev_coefficient<value_type>(static_cast<unsigned>(k), static_cast<unsigned>(i));
0087       }
0088       val /= chebyshev_coefficient<value_type>(static_cast<unsigned>(i), static_cast<unsigned>(i));
0089       result[i] = val;
0090    }
0091    return result;
0092 }
0093 
0094 template <class Seq, class T>
0095 T evaluate_chebyshev(const Seq& a, const T& x)
0096 {
0097    // Clenshaw's formula:
0098    typedef typename Seq::difference_type difference_type;
0099    T yk2 = 0;
0100    T yk1 = 0;
0101    T yk = 0;
0102    for(difference_type i = a.size() - 1; i >= 1; --i)
0103    {
0104       yk2 = yk1;
0105       yk1 = yk;
0106       yk = 2 * x * yk1 - yk2 + a[i];
0107    }
0108    return a[0] / 2 + yk * x - yk1;
0109 }
0110 
0111 
0112 template <typename T>
0113 class polynomial;
0114 
0115 namespace detail {
0116 
0117 /**
0118 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
0119 * Chapter 4.6.1, Algorithm D: Division of polynomials over a field.
0120 *
0121 * @tparam  T   Coefficient type, must be not be an integer.
0122 *
0123 * Template-parameter T actually must be a field but we don't currently have that
0124 * subtlety of distinction.
0125 */
0126 template <typename T, typename N>
0127 typename std::enable_if<!std::numeric_limits<T>::is_integer, void >::type
0128 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
0129 {
0130     q[k] = u[n + k] / v[n];
0131     for (N j = n + k; j > k;)
0132     {
0133         j--;
0134         u[j] -= q[k] * v[j - k];
0135     }
0136 }
0137 
0138 template <class T, class N>
0139 T integer_power(T t, N n)
0140 {
0141    switch(n)
0142    {
0143    case 0:
0144       return static_cast<T>(1u);
0145    case 1:
0146       return t;
0147    case 2:
0148       return t * t;
0149    case 3:
0150       return t * t * t;
0151    }
0152    T result = integer_power(t, n / 2);
0153    result *= result;
0154    if(n & 1)
0155       result *= t;
0156    return result;
0157 }
0158 
0159 
0160 /**
0161 * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
0162 * Chapter 4.6.1, Algorithm R: Pseudo-division of polynomials.
0163 *
0164 * @tparam  T   Coefficient type, must be an integer.
0165 *
0166 * Template-parameter T actually must be a unique factorization domain but we
0167 * don't currently have that subtlety of distinction.
0168 */
0169 template <typename T, typename N>
0170 typename std::enable_if<std::numeric_limits<T>::is_integer, void >::type
0171 division_impl(polynomial<T> &q, polynomial<T> &u, const polynomial<T>& v, N n, N k)
0172 {
0173     q[k] = u[n + k] * integer_power(v[n], k);
0174     for (N j = n + k; j > 0;)
0175     {
0176         j--;
0177         u[j] = v[n] * u[j] - (j < k ? T(0) : u[n + k] * v[j - k]);
0178     }
0179 }
0180 
0181 
0182 /**
0183  * Knuth, The Art of Computer Programming: Volume 2, Third edition, 1998
0184  * Chapter 4.6.1, Algorithm D and R: Main loop.
0185  *
0186  * @param   u   Dividend.
0187  * @param   v   Divisor.
0188  */
0189 template <typename T>
0190 std::pair< polynomial<T>, polynomial<T> >
0191 division(polynomial<T> u, const polynomial<T>& v)
0192 {
0193     BOOST_MATH_ASSERT(v.size() <= u.size());
0194     BOOST_MATH_ASSERT(v);
0195     BOOST_MATH_ASSERT(u);
0196 
0197     typedef typename polynomial<T>::size_type N;
0198 
0199     N const m = u.size() - 1, n = v.size() - 1;
0200     N k = m - n;
0201     polynomial<T> q;
0202     q.data().resize(m - n + 1);
0203 
0204     do
0205     {
0206         division_impl(q, u, v, n, k);
0207     }
0208     while (k-- != 0);
0209     u.data().resize(n);
0210     u.normalize(); // Occasionally, the remainder is zeroes.
0211     return std::make_pair(q, u);
0212 }
0213 
0214 //
0215 // These structures are the same as the void specializations of the functors of the same name
0216 // in the std lib from C++14 onwards:
0217 //
0218 struct negate
0219 {
0220    template <class T>
0221    T operator()(T const &x) const
0222    {
0223       return -x;
0224    }
0225 };
0226 
0227 struct plus
0228 {
0229    template <class T, class U>
0230    T operator()(T const &x, U const& y) const
0231    {
0232       return x + y;
0233    }
0234 };
0235 
0236 struct minus
0237 {
0238    template <class T, class U>
0239    T operator()(T const &x, U const& y) const
0240    {
0241       return x - y;
0242    }
0243 };
0244 
0245 } // namespace detail
0246 
0247 /**
0248  * Returns the zero element for multiplication of polynomials.
0249  */
0250 template <class T>
0251 polynomial<T> zero_element(std::multiplies< polynomial<T> >)
0252 {
0253     return polynomial<T>();
0254 }
0255 
0256 template <class T>
0257 polynomial<T> identity_element(std::multiplies< polynomial<T> >)
0258 {
0259     return polynomial<T>(T(1));
0260 }
0261 
0262 /* Calculates a / b and a % b, returning the pair (quotient, remainder) together
0263  * because the same amount of computation yields both.
0264  * This function is not defined for division by zero: user beware.
0265  */
0266 template <typename T>
0267 std::pair< polynomial<T>, polynomial<T> >
0268 quotient_remainder(const polynomial<T>& dividend, const polynomial<T>& divisor)
0269 {
0270     BOOST_MATH_ASSERT(divisor);
0271     if (dividend.size() < divisor.size())
0272         return std::make_pair(polynomial<T>(), dividend);
0273     return detail::division(dividend, divisor);
0274 }
0275 
0276 
0277 template <class T>
0278 class polynomial
0279 {
0280 public:
0281    // typedefs:
0282    typedef typename std::vector<T>::value_type value_type;
0283    typedef typename std::vector<T>::size_type size_type;
0284 
0285    // construct:
0286    polynomial()= default;
0287 
0288    template <class U>
0289    polynomial(const U* data, unsigned order)
0290       : m_data(data, data + order + 1)
0291    {
0292        normalize();
0293    }
0294 
0295    template <class I>
0296    polynomial(I first, I last)
0297       : m_data(first, last)
0298    {
0299        normalize();
0300    }
0301 
0302    template <class I>
0303    polynomial(I first, unsigned length)
0304       : m_data(first, std::next(first, length + 1))
0305    {
0306        normalize();
0307    }
0308 
0309    polynomial(std::vector<T>&& p) : m_data(std::move(p))
0310    {
0311       normalize();
0312    }
0313 
0314    template <class U, typename std::enable_if<std::is_convertible<U, T>::value, bool>::type = true>
0315    explicit polynomial(const U& point)
0316    {
0317        if (point != U(0))
0318           m_data.push_back(point);
0319    }
0320 
0321    // move:
0322    polynomial(polynomial&& p) noexcept
0323       : m_data(std::move(p.m_data)) { }
0324 
0325    // copy:
0326    polynomial(const polynomial& p)
0327       : m_data(p.m_data) { }
0328 
0329    template <class U>
0330    polynomial(const polynomial<U>& p)
0331    {
0332       m_data.resize(p.size());
0333       for(unsigned i = 0; i < p.size(); ++i)
0334       {
0335          m_data[i] = boost::math::tools::real_cast<T>(p[i]);
0336       }
0337    }
0338 #ifdef BOOST_MATH_HAS_IS_CONST_ITERABLE
0339     template <class Range, typename std::enable_if<boost::math::tools::detail::is_const_iterable<Range>::value, bool>::type = true>
0340     explicit polynomial(const Range& r) 
0341        : polynomial(r.begin(), r.end()) 
0342     {
0343     }
0344 #endif
0345     polynomial(std::initializer_list<T> l) : polynomial(std::begin(l), std::end(l))
0346     {
0347     }
0348 
0349     polynomial&
0350     operator=(std::initializer_list<T> l)
0351     {
0352         m_data.assign(std::begin(l), std::end(l));
0353         normalize();
0354         return *this;
0355     }
0356 
0357 
0358    // access:
0359    size_type size() const { return m_data.size(); }
0360    size_type degree() const
0361    {
0362        if (size() == 0)
0363           BOOST_MATH_THROW_EXCEPTION(std::logic_error("degree() is undefined for the zero polynomial."));
0364        return m_data.size() - 1;
0365    }
0366    value_type& operator[](size_type i)
0367    {
0368       return m_data[i];
0369    }
0370    const value_type& operator[](size_type i) const
0371    {
0372       return m_data[i];
0373    }
0374 
0375    T evaluate(T z) const
0376    {
0377       return this->operator()(z);
0378    }
0379 
0380    T operator()(T z) const
0381    {
0382       return m_data.size() > 0 ? boost::math::tools::evaluate_polynomial((m_data).data(), z, m_data.size()) : T(0);
0383    }
0384    std::vector<T> chebyshev() const
0385    {
0386       return polynomial_to_chebyshev(m_data);
0387    }
0388 
0389    std::vector<T> const& data() const
0390    {
0391        return m_data;
0392    }
0393 
0394    std::vector<T> & data()
0395    {
0396        return m_data;
0397    }
0398 
0399    polynomial<T> prime() const
0400    {
0401 #ifdef _MSC_VER
0402       // Disable int->float conversion warning:
0403 #pragma warning(push)
0404 #pragma warning(disable:4244)
0405 #endif
0406       if (m_data.size() == 0)
0407       {
0408         return polynomial<T>({});
0409       }
0410 
0411       std::vector<T> p_data(m_data.size() - 1);
0412       for (size_t i = 0; i < p_data.size(); ++i) {
0413           p_data[i] = m_data[i+1]*static_cast<T>(i+1);
0414       }
0415       return polynomial<T>(std::move(p_data));
0416 #ifdef _MSC_VER
0417 #pragma warning(pop)
0418 #endif
0419    }
0420 
0421    polynomial<T> integrate() const
0422    {
0423       std::vector<T> i_data(m_data.size() + 1);
0424       // Choose integration constant such that P(0) = 0.
0425       i_data[0] = T(0);
0426       for (size_t i = 1; i < i_data.size(); ++i)
0427       {
0428           i_data[i] = m_data[i-1]/static_cast<T>(i);
0429       }
0430       return polynomial<T>(std::move(i_data));
0431    }
0432 
0433    // operators:
0434    polynomial& operator =(polynomial&& p) noexcept
0435    {
0436        m_data = std::move(p.m_data);
0437        return *this;
0438    }
0439 
0440    polynomial& operator =(const polynomial& p)
0441    {
0442        m_data = p.m_data;
0443        return *this;
0444    }
0445 
0446    template <class U>
0447    typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator +=(const U& value)
0448    {
0449        addition(value);
0450        normalize();
0451        return *this;
0452    }
0453 
0454    template <class U>
0455    typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator -=(const U& value)
0456    {
0457        subtraction(value);
0458        normalize();
0459        return *this;
0460    }
0461 
0462    template <class U>
0463    typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator *=(const U& value)
0464    {
0465       multiplication(value);
0466       normalize();
0467       return *this;
0468    }
0469 
0470    template <class U>
0471    typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator /=(const U& value)
0472    {
0473        division(value);
0474        normalize();
0475        return *this;
0476    }
0477 
0478    template <class U>
0479    typename std::enable_if<std::is_constructible<T, U>::value, polynomial&>::type operator %=(const U& /*value*/)
0480    {
0481        // We can always divide by a scalar, so there is no remainder:
0482        this->set_zero();
0483        return *this;
0484    }
0485 
0486    template <class U>
0487    polynomial& operator +=(const polynomial<U>& value)
0488    {
0489       addition(value);
0490       normalize();
0491       return *this;
0492    }
0493 
0494    template <class U>
0495    polynomial& operator -=(const polynomial<U>& value)
0496    {
0497        subtraction(value);
0498        normalize();
0499        return *this;
0500    }
0501 
0502    template <typename U, typename V>
0503    void multiply(const polynomial<U>& a, const polynomial<V>& b) {
0504        if (!a || !b)
0505        {
0506            this->set_zero();
0507            return;
0508        }
0509        std::vector<T> prod(a.size() + b.size() - 1, T(0));
0510        for (unsigned i = 0; i < a.size(); ++i)
0511            for (unsigned j = 0; j < b.size(); ++j)
0512                prod[i+j] += a.m_data[i] * b.m_data[j];
0513        m_data.swap(prod);
0514    }
0515 
0516    template <class U>
0517    polynomial& operator *=(const polynomial<U>& value)
0518    {
0519       this->multiply(*this, value);
0520       return *this;
0521    }
0522 
0523    template <typename U>
0524    polynomial& operator /=(const polynomial<U>& value)
0525    {
0526        *this = quotient_remainder(*this, value).first;
0527        return *this;
0528    }
0529 
0530    template <typename U>
0531    polynomial& operator %=(const polynomial<U>& value)
0532    {
0533        *this = quotient_remainder(*this, value).second;
0534        return *this;
0535    }
0536 
0537    template <typename U>
0538    polynomial& operator >>=(U const &n)
0539    {
0540        BOOST_MATH_ASSERT(n <= m_data.size());
0541        m_data.erase(m_data.begin(), m_data.begin() + n);
0542        return *this;
0543    }
0544 
0545    template <typename U>
0546    polynomial& operator <<=(U const &n)
0547    {
0548        m_data.insert(m_data.begin(), n, static_cast<T>(0));
0549        normalize();
0550        return *this;
0551    }
0552 
0553    // Convenient and efficient query for zero.
0554    bool is_zero() const
0555    {
0556        return m_data.empty();
0557    }
0558 
0559    // Conversion to bool.
0560    inline explicit operator bool() const
0561    {
0562        return !m_data.empty();
0563    }
0564 
0565    // Fast way to set a polynomial to zero.
0566    void set_zero()
0567    {
0568        m_data.clear();
0569    }
0570 
0571     /** Remove zero coefficients 'from the top', that is for which there are no
0572     *        non-zero coefficients of higher degree. */
0573    void normalize()
0574    {
0575       m_data.erase(std::find_if(m_data.rbegin(), m_data.rend(), [](const T& x)->bool { return x != T(0); }).base(), m_data.end());
0576    }
0577 
0578 private:
0579     template <class U, class R>
0580     polynomial& addition(const U& value, R op)
0581     {
0582         if(m_data.size() == 0)
0583             m_data.resize(1, 0);
0584         m_data[0] = op(m_data[0], value);
0585         return *this;
0586     }
0587 
0588     template <class U>
0589     polynomial& addition(const U& value)
0590     {
0591         return addition(value, detail::plus());
0592     }
0593 
0594     template <class U>
0595     polynomial& subtraction(const U& value)
0596     {
0597         return addition(value, detail::minus());
0598     }
0599 
0600     template <class U, class R>
0601     polynomial& addition(const polynomial<U>& value, R op)
0602     {
0603         if (m_data.size() < value.size())
0604             m_data.resize(value.size(), 0);
0605         for(size_type i = 0; i < value.size(); ++i)
0606             m_data[i] = op(m_data[i], value[i]);
0607         return *this;
0608     }
0609 
0610     template <class U>
0611     polynomial& addition(const polynomial<U>& value)
0612     {
0613         return addition(value, detail::plus());
0614     }
0615 
0616     template <class U>
0617     polynomial& subtraction(const polynomial<U>& value)
0618     {
0619         return addition(value, detail::minus());
0620     }
0621 
0622     template <class U>
0623     polynomial& multiplication(const U& value)
0624     {
0625        std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x * value; });
0626        return *this;
0627     }
0628 
0629     template <class U>
0630     polynomial& division(const U& value)
0631     {
0632        std::transform(m_data.begin(), m_data.end(), m_data.begin(), [&](const T& x)->T { return x / value; });
0633        return *this;
0634     }
0635 
0636     std::vector<T> m_data;
0637 };
0638 
0639 
0640 template <class T>
0641 inline polynomial<T> operator + (const polynomial<T>& a, const polynomial<T>& b)
0642 {
0643    polynomial<T> result(a);
0644    result += b;
0645    return result;
0646 }
0647 
0648 template <class T>
0649 inline polynomial<T> operator + (polynomial<T>&& a, const polynomial<T>& b)
0650 {
0651    a += b;
0652    return std::move(a);
0653 }
0654 template <class T>
0655 inline polynomial<T> operator + (const polynomial<T>& a, polynomial<T>&& b)
0656 {
0657    b += a;
0658    return b;
0659 }
0660 template <class T>
0661 inline polynomial<T> operator + (polynomial<T>&& a, polynomial<T>&& b)
0662 {
0663    a += b;
0664    return a;
0665 }
0666 
0667 template <class T>
0668 inline polynomial<T> operator - (const polynomial<T>& a, const polynomial<T>& b)
0669 {
0670    polynomial<T> result(a);
0671    result -= b;
0672    return result;
0673 }
0674 
0675 template <class T>
0676 inline polynomial<T> operator - (polynomial<T>&& a, const polynomial<T>& b)
0677 {
0678    a -= b;
0679    return a;
0680 }
0681 template <class T>
0682 inline polynomial<T> operator - (const polynomial<T>& a, polynomial<T>&& b)
0683 {
0684    b -= a;
0685    return -b;
0686 }
0687 template <class T>
0688 inline polynomial<T> operator - (polynomial<T>&& a, polynomial<T>&& b)
0689 {
0690    a -= b;
0691    return a;
0692 }
0693 
0694 template <class T>
0695 inline polynomial<T> operator * (const polynomial<T>& a, const polynomial<T>& b)
0696 {
0697    polynomial<T> result;
0698    result.multiply(a, b);
0699    return result;
0700 }
0701 
0702 template <class T>
0703 inline polynomial<T> operator / (const polynomial<T>& a, const polynomial<T>& b)
0704 {
0705    return quotient_remainder(a, b).first;
0706 }
0707 
0708 template <class T>
0709 inline polynomial<T> operator % (const polynomial<T>& a, const polynomial<T>& b)
0710 {
0711    return quotient_remainder(a, b).second;
0712 }
0713 
0714 template <class T, class U>
0715 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator + (polynomial<T> a, const U& b)
0716 {
0717    a += b;
0718    return a;
0719 }
0720 
0721 template <class T, class U>
0722 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator - (polynomial<T> a, const U& b)
0723 {
0724    a -= b;
0725    return a;
0726 }
0727 
0728 template <class T, class U>
0729 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator * (polynomial<T> a, const U& b)
0730 {
0731    a *= b;
0732    return a;
0733 }
0734 
0735 template <class T, class U>
0736 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator / (polynomial<T> a, const U& b)
0737 {
0738    a /= b;
0739    return a;
0740 }
0741 
0742 template <class T, class U>
0743 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator % (const polynomial<T>&, const U&)
0744 {
0745    // Since we can always divide by a scalar, result is always an empty polynomial:
0746    return polynomial<T>();
0747 }
0748 
0749 template <class U, class T>
0750 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator + (const U& a, polynomial<T> b)
0751 {
0752    b += a;
0753    return b;
0754 }
0755 
0756 template <class U, class T>
0757 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator - (const U& a, polynomial<T> b)
0758 {
0759    b -= a;
0760    return -b;
0761 }
0762 
0763 template <class U, class T>
0764 inline typename std::enable_if<std::is_constructible<T, U>::value, polynomial<T> >::type operator * (const U& a, polynomial<T> b)
0765 {
0766    b *= a;
0767    return b;
0768 }
0769 
0770 template <class T>
0771 bool operator == (const polynomial<T> &a, const polynomial<T> &b)
0772 {
0773     return a.data() == b.data();
0774 }
0775 
0776 template <class T>
0777 bool operator != (const polynomial<T> &a, const polynomial<T> &b)
0778 {
0779     return a.data() != b.data();
0780 }
0781 
0782 template <typename T, typename U>
0783 polynomial<T> operator >> (polynomial<T> a, const U& b)
0784 {
0785     a >>= b;
0786     return a;
0787 }
0788 
0789 template <typename T, typename U>
0790 polynomial<T> operator << (polynomial<T> a, const U& b)
0791 {
0792     a <<= b;
0793     return a;
0794 }
0795 
0796 // Unary minus (negate).
0797 template <class T>
0798 polynomial<T> operator - (polynomial<T> a)
0799 {
0800     std::transform(a.data().begin(), a.data().end(), a.data().begin(), detail::negate());
0801     return a;
0802 }
0803 
0804 template <class T>
0805 bool odd(polynomial<T> const &a)
0806 {
0807     return a.size() > 0 && a[0] != static_cast<T>(0);
0808 }
0809 
0810 template <class T>
0811 bool even(polynomial<T> const &a)
0812 {
0813     return !odd(a);
0814 }
0815 
0816 template <class T>
0817 polynomial<T> pow(polynomial<T> base, int exp)
0818 {
0819     if (exp < 0)
0820         return policies::raise_domain_error(
0821                 "boost::math::tools::pow<%1%>",
0822                 "Negative powers are not supported for polynomials.",
0823                 base, policies::policy<>());
0824         // if the policy is ignore_error or errno_on_error, raise_domain_error
0825         // will return std::numeric_limits<polynomial<T>>::quiet_NaN(), which
0826         // defaults to polynomial<T>(), which is the zero polynomial
0827     polynomial<T> result(T(1));
0828     if (exp & 1)
0829         result = base;
0830     /* "Exponentiation by squaring" */
0831     while (exp >>= 1)
0832     {
0833         base *= base;
0834         if (exp & 1)
0835             result *= base;
0836     }
0837     return result;
0838 }
0839 
0840 template <class charT, class traits, class T>
0841 inline std::basic_ostream<charT, traits>& operator << (std::basic_ostream<charT, traits>& os, const polynomial<T>& poly)
0842 {
0843    os << "{ ";
0844    for(unsigned i = 0; i < poly.size(); ++i)
0845    {
0846       if(i) os << ", ";
0847       os << poly[i];
0848    }
0849    os << " }";
0850    return os;
0851 }
0852 
0853 } // namespace tools
0854 } // namespace math
0855 } // namespace boost
0856 
0857 //
0858 // Polynomial specific overload of gcd algorithm:
0859 //
0860 #include <boost/math/tools/polynomial_gcd.hpp>
0861 
0862 #endif // BOOST_MATH_TOOLS_POLYNOMIAL_HPP