2 poly.cc -- routines for manipulation of polynomials in one var
4 (c) 1993--1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 #include "polynomial.hh"
11 Een beter milieu begint bij uzelf. Hergebruik!
14 This was ripped from Rayce, a raytracer I once wrote.
18 Polynomial::eval (Real x)const
23 for (int i = coefs_.size (); i--; )
24 p = x * p + coefs_[i];
31 Polynomial::multiply(const Polynomial & p1, const Polynomial & p2)
35 int deg= p1.degree () + p2.degree ();
36 for (int i = 0; i <= deg; i++)
39 for (int j = 0; j <= i; j++)
40 if (i - j <= p2.degree () && j <= p1.degree ())
41 dest.coefs_.top () += p1.coefs_[j] * p2.coefs_[i - j];
48 Polynomial::differentiate()
50 for (int i = 1; i<= degree (); i++)
52 coefs_[i-1] = coefs_[i] * i;
57 Polynomial::power(int exponent, const Polynomial & src)
60 Polynomial dest(1), base(src);
62 // classicint power. invariant: src^exponent = dest * src ^ e
63 // greetings go out to Lex Bijlsma & Jaap vd Woude
68 dest = multiply(dest, base);
72 base = multiply(base, base);
79 const Real FUDGE = 1e-8;
85 for (i = 0; i <= degree (); i++)
87 if (abs(coefs_[i]) < FUDGE)
91 while (degree () > 0 && fabs (coefs_.top ()) < FUDGE * fabs (coefs_.top (1)))
97 Polynomial::add(const Polynomial & p1, const Polynomial & p2)
100 int tempord = p2.degree () >? p1.degree ();
101 for (int i = 0; i <= tempord; i++)
104 if (i <= p1.degree ())
105 temp += p1.coefs_[i];
106 if (i <= p2.degree ())
107 temp += p2.coefs_[i];
108 dest.coefs_.push (temp);
114 Polynomial::scalarmultiply(Real fact)
116 for (int i = 0; i <= degree (); i++)
121 Polynomial::subtract(const Polynomial & p1, const Polynomial & p2)
124 int tempord = p2.degree () >? p1.degree ();
126 for (int i = 0; i <= tempord; i++)
128 Real temp = 0.0; // can't store result directly.. a=a-b
129 if (i <= p1.degree ())
130 temp += p1.coefs_[i];
131 if (i <= p2.degree ())
132 temp -= p2.coefs_[i];
133 dest.coefs_.push (temp);
140 Polynomial::set_negate(const Polynomial & src)
142 for (int i = 0; i <= src.degree(); i++)
143 coefs_[i] = -src.coefs_[i];
148 Polynomial::set_mod(const Polynomial &u, const Polynomial &v)
153 for (int k = u.degree () - v.degree () - 1; k >= 0; k -= 2)
154 coefs_[k] = -coefs_[k];
156 for (int k = u.degree () - v.degree (); k >= 0; k--)
157 for (int j = v.degree () + k - 1; j >= k; j--)
158 coefs_[j] = -coefs_[j] - coefs_[v.degree () + k] * v.coefs_[j - k];
160 for (int k = u.degree () - v.degree (); k >= 0; k--)
161 for (int j = v.degree () + k - 1; j >= k; j--)
162 coefs_[j] -= coefs_[v.degree () + k] * v.coefs_[j - k];
165 int k = v.degree () - 1;
166 while (k >= 0 && coefs_[k] == 0.0)
169 coefs_.set_size(1+ ( (k < 0) ? 0 : k));
174 Polynomial::check_sol(Real x) const
181 if( abs(f) > abs(d) * FUDGE)
184 warning("x=%f is not a root of polynomial\n"
185 "f(x)=%f, f'(x)=%f \n", x, f, d); */
189 Polynomial::check_sols(Array<Real> roots) const
191 for (int i=0; i< roots.size (); i++)
195 Polynomial::Polynomial (Real a, Real b)
203 inline Real cubic_root(Real x)
206 return pow(x, 1.0/3.0) ;
208 return -pow(-x, 1.0/3.0);
220 Polynomial::solve_cubic()const
224 /* normal form: x^3 + Ax^2 + Bx + C = 0 */
225 Real A = coefs_[2] / coefs_[3];
226 Real B = coefs_[1] / coefs_[3];
227 Real C = coefs_[0] / coefs_[3];
230 * substitute x = y - A/3 to eliminate quadric term: x^3 +px + q = 0
234 Real p = 1.0 / 3 * (-1.0 / 3 * sq_A + B);
235 Real q = 1.0 / 2 * (2.0 / 27 * A * sq_A - 1.0 / 3 * A * B + C);
237 /* use Cardano's formula */
239 Real cb_p = p * p * p;
240 Real D = q * q + cb_p;
243 if (iszero(q)) { /* one triple solution */
247 } else { /* one single and one double solution */
248 Real u = cubic_root(-q);
253 } else if (D < 0) { /* Casus irreducibilis: three real solutions */
254 Real phi = 1.0 / 3 * acos(-q / sqrt(-cb_p));
255 Real t = 2 * sqrt(-p);
257 sol.push (t * cos(phi));
258 sol.push (-t * cos(phi + M_PI / 3));
259 sol.push ( -t * cos(phi - M_PI / 3));
260 } else { /* one real solution */
261 Real sqrt_D = sqrt(D);
262 Real u = cubic_root(sqrt_D - q);
263 Real v = -cubic_root(sqrt_D + q);
269 Real sub = 1.0 / 3 * A;
271 for (int i = sol.size (); i--;)
275 assert (fabs (eval (sol[i]) ) < 1e-8);
282 Polynomial::lc () const
290 return coefs_.top ();
294 Polynomial::degree ()const
296 return coefs_.size () -1;
299 all roots of quadratic eqn.
302 Polynomial::solve_quadric()const
305 /* normal form: x^2 + px + q = 0 */
306 Real p = coefs_[1] / (2 * coefs_[2]);
307 Real q = coefs_[0] / coefs_[2];
320 /* solve linear equation */
322 Polynomial::solve_linear()const
326 s.push ( -coefs_[0] / coefs_[1]);
332 Polynomial::solve () const
334 Polynomial * me = (Polynomial*) this;
340 return solve_linear ();
342 return solve_quadric ();
344 return solve_cubic ();
352 Polynomial:: operator *= (Polynomial const &p2)
354 *this = multiply (*this,p2);
358 Polynomial::operator += (Polynomial const &p)
360 *this = add( *this, p);
364 Polynomial::operator -= (Polynomial const &p)
366 *this = subtract(*this, p);