📄 polynomial.h
字号:
#ifndef POLYNOMIAL_H
#define POLYNOMIAL_H
/**
* This program has been developed by Micha雔 Roy.
* You have the author's permission to incorporate this code
* into your product, royalty free.
* The author specifically disclaims all warranties, express or
* implied, and all liability, including consequential and
* other indirect damages, for the use of this code,
* including liability for infringement of any proprietary
* rights, and including the warranties of merchantability
* and fitness for a particular purpose. And he does not
* assume any responsibility for any errors which may
* appear in this code nor any responsibility to update it.
*
* (c) 2005, Michael Roy. tika1966@yahoo.com
*/
/**
* @file polynomial.h
*
* Polynomial class definition
*
* @ingroup Poly
* @author Michael Roy <a href="mailto:tika1966@yahoo.com">tika1966@yahoo.com</a>
* @version 1.0
*
* @see polyzero.h\n
* laguerre.h\n
* muller.h
*/
#include <vector>
#include <algorithm>
#include <complex>
#include <stdarg.h>
#include "floatspecs.h"
/** @defgroup Poly The Polynomial Templates
* The Polynomial Templates.
*/
/** @defgroup PolyEval Polynomial evaluation functions
* Polynomial evaluation functions.
* @ingroup Poly
*/
/** @defgroup PolyOps Polynomial arithmetics functions
* Polynomial arithmetics functions.
* @ingroup Poly
*/
/** @addtogroup Poly
* @{ */
/**
* defines operations on polynomials.
*
* Class Polynomial is based on the class \p std::vector, and thus
* requires the Standard C++ Library (STL).
*
* Coeficients are stored with lowest degree coeficent first, i.e.: the
* polynomial \f${a_0}+{a_1}x+{a_2}x^2+{a_3}x^3\f$ will be stored
* in the vector as \f$[a_0, a_1, a_2, a_3]\f$.
*
* The coeficient \f$a_0\f$ of degree 0 is always populated. That means
* \p P[0] will always be valid for a polynomial \p P.
*
* Evaluations are made using Horner's recurence, or synthetic division.
*
* Valid types for template parameter \e T are any floating point,
* or complex types which define operators +, -, *, /, and functions abs().
*
* Several constructors are available, the following example shows them and
* their usage.
*
* @par Example:
* @include constructor.cpp
*
* @author Michael Roy <a href="mailto:tika1966@yahoo.com">tika1966@yahoo.com</a>
* @version 0.1
*
* @see polynomial.h for general support function\n
* polyzero.h for polynomial roots support funtions\n
* laguerre.h for roots-finding by Laguerre's method\n
* muller.h for roots-finding by Muller's method
*/
template <class T>
class Polynomial : public std::vector<T> {
public:
/** @name Construction */
/** @{ */
/**
* default constructor.
*
* Creates an empty polynomial of degree zero, you can optionally specify
* a scalar value.
*
* @param[in] a default scalar value for coeficient \f$a_0\f$.
*/
explicit Polynomial(const T& a = T(0)) {
push_back(a);
}
/**
* copy constructor.
*
* Creates an exact copy of Polynomial \f$p\f$
*
* @param[in] p source polynomial.
*
*/
explicit Polynomial(const std::vector<T>& p) : std::vector(p) { }
/**
* initialization constructor.
*
* Initializes a polynomial of arbitrary size and coeficients. Care must be taken
* to properly cast the variable arguments to the same type as template type \e T.
*
* @param[in] n polynomial's degree
* @param[in] a0 degree 0 coeficient
* @param[in] ... coeficients \f$a_1..a_n\f$, number of parameters must match
* parameter \a n.
*/
Polynomial(unsigned n, T a0, ...) {
va_list marker;
int i = n;
if (sizeof(T) != sizeof(float)) {
push_back(a0);
va_start(marker, a0);
while (i-- > 0) {
T an = va_arg(marker, T);
push_back(an);
}
va_end(marker);
compact();
}
else {
// in c/c++, floats are pushed as doubles
push_back(a0);
va_start(marker, a0);
while (i-- > 0) {
double an = va_arg(marker, double);
push_back(T(an));
}
va_end(marker);
compact();
}
}
/** @} construction */
/** @name Methods */
/** @{ */
/**
* compacts array.
*
* Compacts array size to match actual polynomial degree by enforcing
* the rule <i>p[p.size() - 1] != 0</i>.
*
* This function is called by other member functions to enforce the rule
* automatically whenever operations are performed on the polynomial.
*
* @see degree()
*/
void compact() {
while((back() == T(0)) && size() > 1) pop_back();
}
/**
* returns degree of polynomial.
*
* Degree of the polynomial is the index of the highest degree non_null
* coeficient.
*
* @par Example:
* @include degree.cpp
* @par Program output:
* @include degree.txt
*
* @returns the degree of the polynomial.
*
* @see degree()
*/
int degree() const {
int m = (int)size() - 1;
while ((m > 0) &&( (*this)[m] == T(0))) --m;
return m;
}
/**
* returns degree of polynomial.
*
* Degree of the polynomial is the index of the highest degree non_null
* coeficient.
*
* This non-constant version of the function calls compact() before
* returning.
*
* @returns The degree of the polynomial.
*
* @see degree() const
*/
int degree() {
compact();
int m = (int)size() - 1;
if (m < 0) {
resize(1);
m = 0;
}
return (int)size() - 1;
}
/**
* shifts the coeficients.
*
* Shifts the polynomial coeficients left or right, effectively
* doing the operation \f$q(x)=x^{n}p(x)\f$.
*
* If \a n is negative, the remainder of the division
* \f$\frac{p(x)}{x^{-n}}\f$ is lost.
*
* @param[in] n power of multipler \f$x^n\f$.
*/
void shift(int n) {
if (n < 0) {
int newSize = (int)size() + n;
if (newSize >= 1) {
std::copy(&(*this)[-n], &*end(), &(*this)[0]);
}
else {
newSize = 1;
(*this)[0] = T(0);
}
resize(newSize);
}
else if (n > 0) {
resize(size() + n);
std::copy(begin(), end(), begin() + n);
}
}
/**
* makes polynomial monic.
*
* Makes polynomial monic. A polynomial is said monic if its highest
* degree coeficient equals 1.
*
* @see isMonic() const
*/
void makeMonic() {
compact();
if (!isMonic())
*this /= (*this)[degree()];
}
/**
* indicates if polynomial is monic.
* Indicates if polynomial is monic. A polynomial is said monic if its
* highest degree coeficient equals 1.
*
* @returns \p true if polynomial is monic.
*
* @see makeMonic()
*/
inline bool isMonic() const {
return ((*this)[degree()] == T(1));
}
/**
* get derivative of \f$p(x)\f$.
*
* Computes the first derivative polynomial \f$p'(x)\f$ of polynomial \f$p(x)\f$.
*
* @param[out] pp on exit, contains the first derivative \f$p'(x)\f$.
*
* @see evalAndDerive(const T& x, T& ppx) const
*/
void getDerivative(Polynomial<T>& pp) const {
unsigned i;
T ii;
pp.resize(size() - 1);
for (i = 0, ii = T(1); i < pp.size(); ++i, ii += T(1))
pp[i] = ii * (*this)[i + 1];
}
/** @} methods */
/** @name Evaluation */
/** @{ */
/**
* evaluates polynomial value \f$p(x)\f$.
*
* Evaluates \f$p(x)\f$ by Horner's recurence.
*
* No error checking is performed, so any validation for overflow,
* or underflow is the responsibility of the caller.
*
* @param[in] x parameter of \f$p(x)\f$
*
* @returns The value of \f$p(x)\f$.
*/
T eval(const T& x) const {
return ::eval(*this, x);
}
/**
* evaluates polynomial value \e p(a), and computes \f$\frac{p(x)}{(x - a)}\f$.
*
* Evaluates \f$p(a)\f$ and polynomial \f$q(x)=\frac{p(x)-p(a)}{(x - a)}\f$ at the same time
* by Horner's recurence.
*
* It can be shown that \f$p(x)=q(x)(x - a)+p(a)\f$,
* which essentially means that \f$p(a)\f$ is the remainder of
* \f$\frac{p(x)}{(x - a)}\f$. For the special case where \f$a\f$ is a root of
* \f$p(x)\f$ (i.e. \f$p(a)=0\f$), this operation is called
* <i>deflation</i>. That is, on exit \f$q(x)\f$ will have all the roots of
* \f$p(x)\f$, except for the root \f$a\f$.
*
* No error checking is performed, so any validation for overflow,
* or underflow is the responsibility of the caller.
*
* @param[in] a parameter of \f$p(a)\f$.
* @param[out] q on exit contains the quotient \f$q(x)=\frac{p(x)-p(a)}{(x - a)}\f$.
* @returns \f$p(a)\f$, the remainder of \f$\frac{p(x)}{(x - a)}\f$.
*
* @see evalAndDeflate(const Polynomial<T>& p, const U& x, Polynomial<U>& q, V& e)
*/
T evalAndDeflate(const T& a, Polynomial<T>& q) const {
return ::evalAndDeflate(*this, a, q);
}
/**
* evaluates \f$p(x)\f$ and derivate \f$dy=p'(x)\f$ at the same time.
*
* Evaluates efficiently \f$p(x)\f$ and first derivative \f$p'(x)\f$
* at the same time.
*
* @param[in] x variable to evaluate.
* @param[out] ppx on exit contains \f$p'(x)\f$.
* @returns The value of \f$p(x)\f$.
*/
T evalAndDerive(const T& x, T& ppx) const {
int m = degree();
T y;
ppx = 0;
y = (*this)[m];
for (int i = m - 1; i >= 0; --i) {
ppx = (ppx * x) + y;
y = (y * x) + (*this)[i];
}
return y;
}
/** @} evaluation */
/** @name Operators */
/** @{ */
/**
* make a copy of a polynomial.
*
* Make a copy of a polynomial.
*
* @param[in] q polynomial to copy.
*
* @returns A const reference on this object.
*/
inline const Polynomial<T>& operator= (const std::vector<T>& q) {
(std::vector<T>&)*this = q;
return *this;
}
/**
* in-place polynomial addition.
*
* Performs the addition \f$r=p+q\f$, storing the result stored in \p this.
*
* @param[in] q a polynomial.
* @returns A const reference to \p this.
*
* @see operator+ (const Polynomial<T>& p, const Polynomial<T>& q)\n
* Polynomial::operator-= (const Polynomial<T>& A)\n
* add(Polynomial<T>& p, const Polynomial<T>& q)
*/
inline const Polynomial<T>& operator+= (const Polynomial<T>& q) {
add(*this, q);
return *this;
}
/**
* in-place polynomial substraction.
* Performs the substraction \f$r=p-q\f$ and stores the resulting polynomial in
* \p this.
*
* @param[in] q a polynomial.
* @returns A const reference to \p this.
*
* @see operator- (const Polynomial<T>& p, const Polynomial<T>& q)\n
* Polynomial::operator+= (const Polynomial<T>& A)\n
* sub(Polynomial<T>& p, const Polynomial<T>& q)
*/
inline const Polynomial<T>& operator-= (const Polynomial<T>& q) {
sub(*this, q);
return *this;
}
/**
* in-place polynomial multiply.
*
* Multiplies two polynomials by convolution. Performs the operation
* \f$p\leftarrow pq\f$
*
* @param[in] p a polynomial to multiply to \p this object.
* @returns A const reference to this.
*
* @see mul(Polynomial<T> & r, const Polynomial<T>& p, const Polynomial<T>& q)\n
* Polynomial::operator* (const Polynomial<T>& p, const Polynomial<T>& q)
*/
inline const Polynomial<T> operator*= (const Polynomial<T>& p) {
Polynomial<T> q = *this;
mul(*this, p, q);
return *this;
}
/**
* in-place polynomial scaling.
*
* Polynomial scaling, performs the operation \f$p(x)\leftarrow s.p(x)\f$.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -