2 poly.cc -- routines for manipulation of polynomials in one var
4 (c) 1993--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 #include "polynomial.hh"
12 Een beter milieu begint bij uzelf. Hergebruik!
15 This was ripped from Rayce, a raytracer I once wrote.
19 Polynomial::eval (Real x)const
24 for (int i = coefs_.size (); i--;)
25 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;
58 Polynomial::power (int exponent, const Polynomial &src)
61 Polynomial dest (1), base (src);
64 classic int power. invariant: src^exponent = dest * src ^ e
65 greetings go out to Lex Bijlsma & Jaap vd Woude */
70 dest = multiply (dest, base);
76 base = multiply (base, base);
83 static Real const FUDGE = 1e-8;
89 We only do relative comparisons. Absolute comparisons break down in
92 && (fabs (coefs_.top ()) < FUDGE *fabs (coefs_.top (1))
98 Polynomial::operator+= (Polynomial const &p)
100 while (degree () < p.degree ())
103 for (int i = 0; i <= p.degree (); i++)
104 coefs_[i] += p.coefs_[i];
108 Polynomial::operator-= (Polynomial const &p)
110 while (degree () < p.degree ())
113 for (int i = 0; i <= p.degree (); i++)
114 coefs_[i] -= p.coefs_[i];
118 Polynomial::scalarmultiply (Real fact)
120 for (int i = 0; i <= degree (); i++)
125 Polynomial::set_negate (const Polynomial &src)
127 for (int i = 0; i <= src.degree (); i++)
128 coefs_[i] = -src.coefs_[i];
133 Polynomial::set_mod (const Polynomial &u, const Polynomial &v)
139 for (int k = u.degree () - v.degree () - 1; k >= 0; k -= 2)
140 coefs_[k] = -coefs_[k];
142 for (int k = u.degree () - v.degree (); k >= 0; k--)
143 for (int j = v.degree () + k - 1; j >= k; j--)
144 coefs_[j] = -coefs_[j] - coefs_[v.degree () + k] * v.coefs_[j - k];
149 for (int k = u.degree () - v.degree (); k >= 0; k--)
150 for (int j = v.degree () + k - 1; j >= k; j--)
151 coefs_[j] -= coefs_[v.degree () + k] * v.coefs_[j - k];
154 int k = v.degree () - 1;
155 while (k >= 0 && coefs_[k] == 0.0)
158 coefs_.set_size (1+ ((k < 0) ? 0 : k));
163 Polynomial::check_sol (Real x) const
166 Polynomial p (*this);
170 if (abs (f) > abs (d) * FUDGE);
172 warning ("x=%f is not a root of polynomial\n"
173 "f (x)=%f, f' (x)=%f \n", x, f, d); */
177 Polynomial::check_sols (Array<Real> roots) const
179 for (int i = 0; i< roots.size (); i++)
180 check_sol (roots[i]);
183 Polynomial::Polynomial (Real a, Real b)
191 inline Real cubic_root (Real x)
194 return pow (x, 1.0 / 3.0);
196 return -pow (-x, 1.0 / 3.0);
208 Polynomial::solve_cubic ()const
212 /* normal form: x^3 + Ax^2 + Bx + C = 0 */
213 Real A = coefs_[2] / coefs_[3];
214 Real B = coefs_[1] / coefs_[3];
215 Real C = coefs_[0] / coefs_[3];
218 * substitute x = y - A/3 to eliminate quadric term: x^3 +px + q = 0
222 Real p = 1.0 / 3 * (-1.0 / 3 * sq_A + B);
223 Real q = 1.0 / 2 * (2.0 / 27 * A *sq_A - 1.0 / 3 * A *B + C);
225 /* use Cardano's formula */
232 if (iszero (q)) { /* one triple solution */
236 } else { /* one single and one double solution */
237 Real u = cubic_root (-q);
242 } else if (D < 0) { /* Casus irreducibilis: three real solutions */
243 Real phi = 1.0 / 3 * acos (-q / sqrt (-cb));
244 Real t = 2 * sqrt (-p);
246 sol.push (t * cos (phi));
247 sol.push (-t * cos (phi + M_PI / 3));
248 sol.push (-t * cos (phi - M_PI / 3));
249 } else { /* one real solution */
250 Real sqrt_D = sqrt (D);
251 Real u = cubic_root (sqrt_D - q);
252 Real v = -cubic_root (sqrt_D + q);
258 Real sub = 1.0 / 3 * A;
260 for (int i = sol.size (); i--;)
265 assert (fabs (eval (sol[i])) < 1e-8);
273 Polynomial::lc () const
275 return coefs_.top ();
281 return coefs_.top ();
285 Polynomial::degree ()const
287 return coefs_.size () -1;
290 all roots of quadratic eqn.
293 Polynomial::solve_quadric ()const
296 /* normal form: x^2 + px + q = 0 */
297 Real p = coefs_[1] / (2 * coefs_[2]);
298 Real q = coefs_[0] / coefs_[2];
312 /* solve linear equation */
314 Polynomial::solve_linear ()const
318 s.push (-coefs_[0] / coefs_[1]);
323 Polynomial::solve () const
325 Polynomial *me = (Polynomial *) this;
331 return solve_linear ();
333 return solve_quadric ();
335 return solve_cubic ();
342 Polynomial:: operator*= (Polynomial const &p2)
344 *this = multiply (*this, p2);