Theoretica
Mathematical Library
Loading...
Searching...
No Matches
polynomial.h
Go to the documentation of this file.
1
5
6#ifndef THEORETICA_POLYNOMIAL_H
7#define THEORETICA_POLYNOMIAL_H
8
9#ifndef THEORETICA_NO_PRINT
10#include <sstream>
11#include <ostream>
12#endif
13
14#include "../core/real_analysis.h"
15#include "../algebra/vec.h"
16#include "../complex/complex.h"
17#include "../complex/complex_analysis.h"
18
19
20namespace theoretica {
21
24 template<typename Type = real>
25 class polynomial {
26 public:
27 std::vector<Type> coeff;
28
30 polynomial() : coeff() {}
31
33 polynomial(Type a) : coeff({a}) {}
34
36 polynomial(const std::vector<Type>& c) : coeff(c) {}
37
39 polynomial(std::initializer_list<Type> l) : coeff(l) {}
40
43
44
46 inline const Type& at(unsigned int i) const {
47 return coeff.at(i);
48 }
49
51 inline Type& at(unsigned int i) {
52 return coeff.at(i);
53 }
54
55
57 inline const Type& operator[](unsigned int i) const {
58 return coeff[i];
59 }
60
61
63 inline Type& operator[](unsigned int i) {
64 return coeff[i];
65 }
66
67
69 template<typename EvalType = Type>
70 inline EvalType eval(EvalType x) const {
71
72 if(!coeff.size())
73 return 0;
74
75 EvalType sum = 0;
76
77 // Evaluate using Horner's method
78 for (unsigned int i = 0; i < coeff.size(); ++i)
79 sum = coeff[coeff.size() - i - 1] + x * sum;
80
81 return sum;
82 }
83
84
86 template<typename EvalType = Type>
87 inline EvalType operator()(EvalType x) const {
88 return eval(x);
89 }
90
91
94 inline unsigned int find_order() const {
95
96 for (int i = coeff.size() - 1; i >= 0; --i) {
97 if(abs(coeff[i]) < MACH_EPSILON)
98 return i;
99 }
100
101 return 0;
102 }
103
104
106 inline void trim() {
107
108 for (unsigned int i = coeff.size() - 1; i >= 0; --i) {
109 if(abs(coeff[i]) > MACH_EPSILON)
110 break;
111
112 coeff.pop_back();
113 }
114 }
115
116
118 inline size_t size() const {
119 return coeff.size();
120 }
121
122
124 inline polynomial operator+(const polynomial& p) const {
125
126 polynomial r;
127 r.coeff.resize(max(coeff.size(), p.size()));
128
129 unsigned int i = 0;
130
131 for (; i < min(coeff.size(), p.size()); ++i)
132 r[i] = coeff[i] + p[i];
133
134 if (coeff.size() > p.size())
135 for (; i < coeff.size(); ++i)
136 r[i] = coeff[i];
137 else
138 for (; i < p.size(); ++i)
139 r[i] = p[i];
140
141 return r;
142 }
143
144
146 inline polynomial operator-(const polynomial& p) const {
147
148 polynomial r;
149 r.coeff.resize(max(coeff.size(), p.size()));
150
151 unsigned int i = 0;
152
153 for (; i < min(r.size(), p.size()); ++i)
154 r[i] = coeff[i] - p[i];
155
156 if (coeff.size() > p.size())
157 for (; i < coeff.size(); ++i)
158 r[i] = coeff[i];
159 else
160 for (; i < p.size(); ++i)
161 r[i] = -p[i];
162
163 return r;
164 }
165
166
168 inline polynomial operator*(const polynomial& p) const {
169
171 r.coeff.resize(this->size() + p.size() - 1);
172
173 for (unsigned int i = 0; i < size(); ++i) {
174 for (unsigned int j = 0; j < p.size(); ++j) {
175 r[i + j] += coeff[i] * p[j];
176 }
177 }
178
179 return r;
180 }
181
182
184 inline polynomial operator/(const polynomial& d) const {
185
186 const unsigned int d_order = d.find_order();
187 const unsigned int this_order = find_order();
188
189 if(d_order == 0 && d[0] == 0) {
190 TH_MATH_ERROR("polynomial::operator/", d[0], DIV_BY_ZERO);
191 return polynomial(nan());
192 }
193
194 // Remainder
195 polynomial r = *this;
196
197 // Quotient
199 unsigned int i = 0;
200
201 while(i < this_order) {
202
203 // Compute only once the degree of the polynomial
204 const unsigned int r_order = r.find_order();
205
206 // Stop execution if the division is complete
207 // (when the remainder is 0 or has lower degree)
208 if((r_order == 0 && (abs(r[0]) < MACH_EPSILON)) || r_order < d_order)
209 break;
210
211 // Simple division between highest degree terms
213 r[r_order] / d[d_order],
214 r_order - d_order);
215
216 // Add monomial to quotient and subtract the
217 // monomial times the dividend from the remainder
218 q += t;
219 r -= t * d;
220
221 i++;
222 }
223
224 // The algorithm has stopped iterating after a number
225 // of the dividend's degree counts
226 if(i == this_order) {
227 TH_MATH_ERROR("polynomial::operator/", i, NO_ALGO_CONVERGENCE);
228 return polynomial(nan());
229 }
230
231 return q;
232 }
233
234
236 inline polynomial operator*(Type a) const {
237
238 polynomial r = polynomial(*this);
239
240 for (unsigned int i = 0; i < size(); ++i)
241 r.coeff[i] *= a;
242
243 return r;
244 }
245
246
248 inline polynomial operator/(Type a) const {
249
250 if(abs(a) < MACH_EPSILON) {
251 TH_MATH_ERROR("polynomial::operator/", a, DIV_BY_ZERO);
252 }
253
254 polynomial r = polynomial(*this);
255
256 for (unsigned int i = 0; i < size(); ++i)
257 r.coeff[i] /= a;
258
259 return r;
260 }
261
262
264 inline polynomial& operator+=(const polynomial& p) {
265
266 // Make room for the new coefficients
267 if(coeff.size() < p.size())
268 coeff.resize(p.size(), Type(0));
269
270 for (unsigned int i = 0; i < min(size(), p.size()); ++i)
271 coeff[i] += p[i];
272
273 return *this;
274 }
275
276
278 inline polynomial& operator-=(const polynomial& p) {
279
280 // Make room for the new coefficients
281 if(coeff.size() < p.size())
282 coeff.resize(p.size(), Type(0));
283
284 for (unsigned int i = 0; i < min(coeff.size(), p.size()); ++i)
285 coeff[i] -= p[i];
286
287 return *this;
288 }
289
290
292 inline polynomial& operator*=(const polynomial& p) {
293
295 r.coeff.resize(this->size() + p.size() - 1, Type(0));
296
297 for (unsigned int i = 0; i < coeff.size(); ++i)
298 for (unsigned int j = 0; j < p.size(); ++j)
299 r[i + j] += coeff[i] * p[j];
300
301 *this = r;
302 return *this;
303 }
304
305
307 inline polynomial& operator*=(Type a) {
308
309 for (unsigned int i = 0; i < coeff.size(); ++i)
310 coeff[i] *= a;
311
312 return *this;
313 }
314
315
317 inline polynomial& operator/=(const polynomial& a) {
318 return (*this = (*this / a));
319 }
320
321
323 inline polynomial& operator/=(Type a) {
324
325 if(abs(a) < MACH_EPSILON) {
326 TH_MATH_ERROR("polynomial::operator/=", a, DIV_BY_ZERO);
327 return *this;
328 }
329
330 for (unsigned int i = 0; i < coeff.size(); ++i)
331 coeff[i] /= a;
332
333 return *this;
334 }
335
336
338 inline bool operator==(const polynomial& other) const {
339
340 const unsigned int n = min(other.size(), this->size());
341 for (unsigned int i = 0; i < n; ++i) {
342 if(abs(other.coeff[i] - coeff[i]) >= MACH_EPSILON)
343 return false;
344 }
345
346 if(size() > other.size()) {
347 for (unsigned int i = 0; i < size(); ++i) {
348 if(abs(coeff[i]) >= MACH_EPSILON)
349 return false;
350 }
351 } else {
352 for (unsigned int i = 0; i < other.size(); ++i) {
353 if(abs(other.coeff[i]) >= MACH_EPSILON)
354 return false;
355 }
356 }
357
358 return true;
359 }
360
361
364 inline auto begin() {
365 return coeff.begin();
366 }
367
368
371 inline auto end() {
372 return coeff.end();
373 }
374
375
378 inline auto cbegin() {
379 return coeff.cbegin();
380 }
381
382
385 inline auto cend() {
386 return coeff.cend();
387 }
388
389
391 inline vec<complex<>, 2> quadratic_roots() const {
392
393 const int order = find_order();
394
395 // Check that the polynomial is quadratic
396 if(order != 2) {
397 TH_MATH_ERROR("quadratic_roots", order, IMPOSSIBLE_OPERATION);
398 return vec<complex<>, 2>({nan(), nan()});
399 }
400
401 const Type p = coeff[1] / coeff[2];
402 const Type q = coeff[0] / coeff[2];
403
404 // Case when 0 is a root
405 if(abs(q) < MACH_EPSILON)
406 return {complex<>(-p), complex<>(0)};
407
408 complex<> z1, z2;
409
410 // Use Vieta's theorem to avoid catastrophic cancellation
411 if(abs(p) > 1) {
412
413 z1 = -sgn(p) * (abs(p) / 2.0
414 + abs(p) * sqrt(complex<>(0.25 - (q / p) / p)));
415 z2 = q / z1;
416
417 } else {
418
419 const complex<> s = sqrt(complex<>(0.25 * square(p) - q));
420 z1 = -p / 2.0 + s;
421 z2 = -p / 2.0 - s;
422 }
423
424 return {z1, z2};
425 }
426
427
429 inline static polynomial<Type> from_roots(
430 const std::vector<Type>& roots) {
431
432 polynomial<Type> P = {1};
433
434 // P = product((x - r_i))
435 for (unsigned int i = 0; i < roots.size(); ++i)
436 P *= polynomial<Type>({roots[i] * -1, 1});
437
438 return P;
439 }
440
441
443 inline static polynomial<Type> monomial(Type c, unsigned int order) {
444
445 polynomial m;
446 m.coeff = std::vector<Type>(order + 1, Type(0));
447 m.coeff[order] = c;
448 return m;
449 }
450
451
452 // Friend operators to enable equations of the form
453 // (Type) op. (polynomial<Type>)
454
455 inline friend polynomial<Type> operator+(
456 Type r, const polynomial<Type>& z) {
457
458 return z + polynomial(r);
459 }
460
461 inline friend polynomial<Type> operator-(
462 Type r, const polynomial<Type>& z) {
463
464 return (z * -1) + polynomial(r);
465 }
466
467 inline friend polynomial<Type> operator*(
468 Type r, const polynomial<Type>& z) {
469
470 return z * r;
471 }
472
473
474#ifndef THEORETICA_NO_PRINT
475
477 inline std::string to_string(
478 const std::string& unknown = "x",
479 const std::string& exponentiation = "^") const {
480
481 std::stringstream res;
482 bool flag = false;
483 const int sz = coeff.size();
484
485 for (int i = sz - 1; i >= 0; --i) {
486
487 if(abs(coeff[i]) < MACH_EPSILON)
488 continue;
489
490 res << (coeff[i] >= 0 ? "+ " : "- ");
491 res << abs(coeff[i]);
492
493 if(i) {
494 res << "*" << unknown << exponentiation << i;
495 res << " ";
496 }
497
498 flag = true;
499 }
500
501 if(!flag)
502 res << "0";
503
504 return res.str();
505 }
506
507
509 inline operator std::string() {
510 return to_string();
511 }
512
513
516 friend std::ostream& operator<<(std::ostream& out, const polynomial& obj) {
517 return out << obj.to_string();
518 }
519
520#endif
521
522
523 };
524
525}
526
527#endif
A polynomial of arbitrary order.
Definition polynomial.h:25
polynomial & operator/=(const polynomial &a)
Multiply a polynomial by a scalar value.
Definition polynomial.h:317
polynomial & operator+=(const polynomial &p)
Sum a polynomial to this one.
Definition polynomial.h:264
~polynomial()
Default destructor.
Definition polynomial.h:42
auto begin()
Get an iterator for the first coefficient of the polynomial.
Definition polynomial.h:364
polynomial(std::initializer_list< Type > l)
Initialize from an std::initializer_list.
Definition polynomial.h:39
polynomial(const std::vector< Type > &c)
Initialize from an std::vector.
Definition polynomial.h:36
auto cbegin()
Get a const iterator for the first coefficient of the polynomial.
Definition polynomial.h:378
EvalType eval(EvalType x) const
Evaluate the polynomial using x as variable.
Definition polynomial.h:70
polynomial operator/(const polynomial &d) const
Polynomial division.
Definition polynomial.h:184
void trim()
Remove trailing zero coefficients.
Definition polynomial.h:106
EvalType operator()(EvalType x) const
Evaluate the polynomial using x as variable.
Definition polynomial.h:87
polynomial & operator*=(const polynomial &p)
Multiply two polynomials.
Definition polynomial.h:292
Type & at(unsigned int i)
Access i-th coefficient by reference, with bound checking.
Definition polynomial.h:51
polynomial(Type a)
Initialize as a constant.
Definition polynomial.h:33
auto end()
Get an iterator for the one plus last coefficient of the polynomial.
Definition polynomial.h:371
vec< complex<>, 2 > quadratic_roots() const
Compute the roots of a quadratic polynomial.
Definition polynomial.h:391
friend std::ostream & operator<<(std::ostream &out, const polynomial &obj)
Stream the polynomial in string representation to an output stream (std::ostream)
Definition polynomial.h:516
polynomial & operator-=(const polynomial &p)
Subtract a polynomial from this one.
Definition polynomial.h:278
const Type & operator[](unsigned int i) const
Get the n-th order coefficient by constant reference.
Definition polynomial.h:57
static polynomial< Type > monomial(Type c, unsigned int order)
Returns a monomial of the given degree and coefficient.
Definition polynomial.h:443
bool operator==(const polynomial &other) const
Check whether two polynomials are equal.
Definition polynomial.h:338
polynomial operator*(const polynomial &p) const
Multiply two polynomials.
Definition polynomial.h:168
polynomial & operator/=(Type a)
Divide a polynomial by a scalar value.
Definition polynomial.h:323
const Type & at(unsigned int i) const
Get i-th coefficient by constant reference, with bound checking.
Definition polynomial.h:46
Type & operator[](unsigned int i)
Get the n-th order coefficient by reference.
Definition polynomial.h:63
polynomial()
Initialize as an empty polynomial.
Definition polynomial.h:30
unsigned int find_order() const
Find the true order of the polynomial (ignoring trailing null coefficients)
Definition polynomial.h:94
auto cend()
Get a const iterator for the one plus last coefficient of the polynomial.
Definition polynomial.h:385
size_t size() const
Get the number of coefficients.
Definition polynomial.h:118
polynomial operator+(const polynomial &p) const
Sum two polynomials.
Definition polynomial.h:124
polynomial operator-(const polynomial &p) const
Subtract a polynomial from another.
Definition polynomial.h:146
polynomial operator/(Type a) const
Divide a polynomial by a scalar.
Definition polynomial.h:248
std::string to_string(const std::string &unknown="x", const std::string &exponentiation="^") const
Convert the polynomial to string representation.
Definition polynomial.h:477
polynomial & operator*=(Type a)
Multiply a polynomial by a scalar value.
Definition polynomial.h:307
polynomial operator*(Type a) const
Multiply a polynomial by a scalar.
Definition polynomial.h:236
static polynomial< Type > from_roots(const std::vector< Type > &roots)
Construct a polynomial from its roots.
Definition polynomial.h:429
#define TH_MATH_ERROR(F_NAME, VALUE, EXCEPTION)
TH_MATH_ERROR is a macro which throws exceptions or modifies errno (depending on which compiling opti...
Definition error.h:225
Main namespace of the library which contains all functions and objects.
Definition algebra.h:27
auto min(const Vector &X)
Finds the minimum value inside a dataset.
Definition dataset.h:351
dual2 sqrt(dual2 x)
Compute the square root of a second order dual number.
Definition dual2_functions.h:54
dual2 abs(dual2 x)
Compute the absolute value of a second order dual number.
Definition dual2_functions.h:198
auto sum(const Vector &X)
Compute the sum of a vector of real values using pairwise summation to reduce round-off error.
Definition dataset.h:219
std::vector< real > roots(RealFunction f, real a, real b, real tol=OPTIMIZATION_TOL, real steps=10)
Find the roots of a univariate real function inside a given interval, by first searching for candidat...
Definition roots.h:650
auto max(const Vector &X)
Finds the maximum value inside a dataset.
Definition dataset.h:330
TH_CONSTEXPR real nan()
Return a quiet NaN number in floating point representation.
Definition error.h:54
constexpr real MACH_EPSILON
Machine epsilon for the real type.
Definition constants.h:207
int sgn(real x)
Return the sign of x (1 if positive, -1 if negative, 0 if null)
Definition real_analysis.h:259
dual2 square(dual2 x)
Return the square of a second order dual number.
Definition dual2_functions.h:23