(print): return '() for height == 0.0 too.
[lilypond.git] / flower / polynomial.cc
bloba6ee02d183293c37a3eda00f9a730e18c0ebd659
1 /*
2 poly.cc -- routines for manipulation of polynomials in one var
4 (c) 1993--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
5 */
7 #include <math.h>
9 #include "polynomial.hh"
12 Een beter milieu begint bij uzelf. Hergebruik!
15 This was ripped from Rayce, a raytracer I once wrote.
18 Real
19 Polynomial::eval (Real x)const
21 Real p = 0.0;
23 // horner's scheme
24 for (int i = coefs_.size (); i--; )
25 p = x * p + coefs_[i];
27 return p;
31 Polynomial
32 Polynomial::multiply (const Polynomial & p1, const Polynomial & p2)
34 Polynomial dest;
36 int deg= p1.degree () + p2.degree ();
37 for (int i = 0; i <= deg; i++)
39 dest.coefs_.push (0);
40 for (int j = 0; j <= i; j++)
41 if (i - j <= p2.degree () && j <= p1.degree ())
42 dest.coefs_.top () += p1.coefs_[j] * p2.coefs_[i - j];
45 return dest;
48 void
49 Polynomial::differentiate ()
51 for (int i = 1; i<= degree (); i++)
53 coefs_[i-1] = coefs_[i] * i;
55 coefs_.pop ();
58 Polynomial
59 Polynomial::power (int exponent, const Polynomial & src)
61 int e = exponent;
62 Polynomial dest (1), base (src);
65 classic int power. invariant: src^exponent = dest * src ^ e
66 greetings go out to Lex Bijlsma & Jaap vd Woude */
67 while (e > 0)
69 if (e % 2)
71 dest = multiply (dest, base);
72 e--;
73 } else
75 base = multiply (base, base);
76 e /= 2;
79 return dest;
82 static Real const FUDGE = 1e-8;
84 void
85 Polynomial::clean ()
88 We only do relative comparisons. Absolute comparisons break down in
89 degenerate cases. */
90 while (degree () > 0 &&
91 (fabs (coefs_.top ()) < FUDGE * fabs (coefs_.top (1))
92 || !coefs_.top ()))
93 coefs_.pop ();
98 void
99 Polynomial::operator += (Polynomial const &p)
101 while (degree () < p.degree())
102 coefs_.push (0.0);
104 for (int i = 0; i <= p.degree(); i++)
105 coefs_[i] += p.coefs_[i];
109 void
110 Polynomial::operator -= (Polynomial const &p)
112 while (degree () < p.degree())
113 coefs_.push (0.0);
115 for (int i = 0; i <= p.degree(); i++)
116 coefs_[i] -= p.coefs_[i];
120 void
121 Polynomial::scalarmultiply (Real fact)
123 for (int i = 0; i <= degree (); i++)
124 coefs_[i] *= fact;
129 void
130 Polynomial::set_negate (const Polynomial & src)
132 for (int i = 0; i <= src.degree (); i++)
133 coefs_[i] = -src.coefs_[i];
136 /// mod of #u/v#
137 int
138 Polynomial::set_mod (const Polynomial &u, const Polynomial &v)
140 (*this) = u;
142 if (v.lc () < 0.0) {
143 for (int k = u.degree () - v.degree () - 1; k >= 0; k -= 2)
144 coefs_[k] = -coefs_[k];
146 for (int k = u.degree () - v.degree (); k >= 0; k--)
147 for (int j = v.degree () + k - 1; j >= k; j--)
148 coefs_[j] = -coefs_[j] - coefs_[v.degree () + k] * v.coefs_[j - k];
149 } else {
150 for (int k = u.degree () - v.degree (); k >= 0; k--)
151 for (int j = v.degree () + k - 1; j >= k; j--)
152 coefs_[j] -= coefs_[v.degree () + k] * v.coefs_[j - k];
155 int k = v.degree () - 1;
156 while (k >= 0 && coefs_[k] == 0.0)
157 k--;
159 coefs_.set_size (1+ ((k < 0) ? 0 : k));
160 return degree ();
163 void
164 Polynomial::check_sol (Real x) const
166 Real f=eval (x);
167 Polynomial p (*this);
168 p.differentiate ();
169 Real d = p.eval (x);
171 if ( abs (f) > abs (d) * FUDGE)
174 warning ("x=%f is not a root of polynomial\n"
175 "f (x)=%f, f' (x)=%f \n", x, f, d); */
178 void
179 Polynomial::check_sols (Array<Real> roots) const
181 for (int i=0; i< roots.size (); i++)
182 check_sol (roots[i]);
185 Polynomial::Polynomial (Real a, Real b)
187 coefs_.push (a);
188 if (b)
189 coefs_.push (b);
192 /* cubic root. */
193 inline Real cubic_root (Real x)
195 if (x > 0.0)
196 return pow (x, 1.0/3.0) ;
197 else if (x < 0.0)
198 return -pow (-x, 1.0/3.0);
199 else
200 return 0.0;
203 static bool
204 iszero (Real r)
206 return !r;
209 Array<Real>
210 Polynomial::solve_cubic ()const
212 Array<Real> sol;
214 /* normal form: x^3 + Ax^2 + Bx + C = 0 */
215 Real A = coefs_[2] / coefs_[3];
216 Real B = coefs_[1] / coefs_[3];
217 Real C = coefs_[0] / coefs_[3];
220 * substitute x = y - A/3 to eliminate quadric term: x^3 +px + q = 0
223 Real sq_A = A * A;
224 Real p = 1.0 / 3 * (-1.0 / 3 * sq_A + B);
225 Real q = 1.0 / 2 * (2.0 / 27 * A * sq_A - 1.0 / 3 * A * B + C);
227 /* use Cardano's formula */
229 Real cb = p * p * p;
230 Real D = q * q + cb;
232 if (iszero (D)) {
233 if (iszero (q)) { /* one triple solution */
234 sol.push (0);
235 sol.push (0);
236 sol.push (0);
237 } else { /* one single and one double solution */
238 Real u = cubic_root (-q);
240 sol.push (2 * u);
241 sol.push (-u);
243 } else if (D < 0) { /* Casus irreducibilis: three real solutions */
244 Real phi = 1.0 / 3 * acos (-q / sqrt (-cb));
245 Real t = 2 * sqrt (-p);
247 sol.push (t * cos (phi));
248 sol.push (-t * cos (phi + M_PI / 3));
249 sol.push ( -t * cos (phi - M_PI / 3));
250 } else { /* one real solution */
251 Real sqrt_D = sqrt (D);
252 Real u = cubic_root (sqrt_D - q);
253 Real v = -cubic_root (sqrt_D + q);
255 sol.push ( u + v);
258 /* resubstitute */
259 Real sub = 1.0 / 3 * A;
261 for (int i = sol.size (); i--;)
263 sol[i] -= sub;
265 #ifdef PARANOID
266 assert (fabs (eval (sol[i]) ) < 1e-8);
267 #endif
270 return sol;
273 Real
274 Polynomial::lc () const
276 return coefs_.top ();
279 Real&
280 Polynomial::lc ()
282 return coefs_.top ();
286 Polynomial::degree ()const
288 return coefs_.size () -1;
291 all roots of quadratic eqn.
293 Array<Real>
294 Polynomial::solve_quadric ()const
296 Array<Real> sol;
297 /* normal form: x^2 + px + q = 0 */
298 Real p = coefs_[1] / (2 * coefs_[2]);
299 Real q = coefs_[0] / coefs_[2];
301 Real D = p * p - q;
303 if (D>0) {
304 D = sqrt (D);
306 sol.push ( D - p);
307 sol.push ( -D - p);
309 return sol;
312 /* solve linear equation */
313 Array<Real>
314 Polynomial::solve_linear ()const
316 Array<Real> s;
317 if (coefs_[1])
318 s.push ( -coefs_[0] / coefs_[1]);
319 return s;
323 Array<Real>
324 Polynomial::solve () const
326 Polynomial * me = (Polynomial*) this;
327 me->clean ();
329 switch (degree ())
331 case 1:
332 return solve_linear ();
333 case 2:
334 return solve_quadric ();
335 case 3:
336 return solve_cubic ();
338 Array<Real> s;
339 return s;
342 void
343 Polynomial:: operator *= (Polynomial const &p2)
345 *this = multiply (*this,p2);