PLUTO
quartic.old.c
Go to the documentation of this file.
1 /* ///////////////////////////////////////////////////////////////////// */
2 /*!
3  \file
4  \brief Solve quartic and cubic equations-
5 
6 
7  \author A. Mignone (mignone@ph.unito.it)
8  \date Sept 10, 2012
9 */
10 /* ///////////////////////////////////////////////////////////////////// */
11 #include "pluto.h"
12 #include "complex.h"
13 
14 /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
15  These two functions may be moved into tools.c
16  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
17 
18 #define swap(x,y) f = x; x = y; y = f;
19 
20 /* ********************************************************************* */
21 int QuarticSolve (double b, double c, double d, double e, double *z)
22 /*!
23  * Solve a quartic equation in the form
24  * \f[
25  * z^4 + bz^3 + cz^2 + dz + e = 0
26  * \f]
27  * For its purpose, it is assumed that \b ALL roots are double.
28  * This makes things faster.
29  *
30  * \param [in] b coefficient of the quartic
31  * \param [in] c coefficient of the quartic
32  * \param [in] d coefficient of the quartic
33  * \param [in] e coefficient of the quartic
34  * \param [out] z vector containing the
35  * (double) roots of the quartic
36  *
37  * \b Reference:
38  *
39  * http://www.1728.com/quartic2.htm
40  *
41  * \return Return 0 on success, 1 if cubic solver fails, 2 if NaN has
42  * been found and 3 if quartic is not satisfied.
43  *
44  *********************************************************************** */
45 {
46  int n, j, ifail;
47  double b2, f, g, h;
48  double a2, a1, a0, u[4];
49  double p, q, r, s;
50  static double three_256 = 3.0/256.0;
51  static double one_64 = 1.0/64.0;
52 
53  b2 = b*b;
54 
55  f = c - b2*0.375;
56  g = d + b2*b*0.125 - b*c*0.5;
57  h = e - b2*b2*three_256 + 0.0625*b2*c - 0.25*b*d;
58 
59  a2 = 0.5*f;
60  a1 = (f*f - 4.0*h)*0.0625;
61  a0 = -g*g*one_64;
62 
63  ifail = CubicSolve(a2, a1, a0, u);
64 
65  if (ifail) return 1;
66 
67  if (u[1] < 1.e-14){
68 
69  p = sqrt(u[2]);
70  s = 0.25*b;
71  z[0] = z[2] = - p - s;
72  z[1] = z[3] = + p - s;
73 
74  }else{
75 
76  p = sqrt(u[1]);
77  q = sqrt(u[2]);
78 
79  r = -0.125*g/(p*q);
80  s = 0.25*b;
81 
82  z[0] = - p - q + r - s;
83  z[1] = p - q - r - s;
84  z[2] = - p + q - r - s;
85  z[3] = p + q + r - s;
86 
87  }
88 
89 /* ----------------------------------------
90  Sort roots in ascending order.
91  Since z[0] < z[3], we first order
92 
93  z[0] < z[1] < z[3]
94 
95  and then put z[2] into the sequence.
96  ---------------------------------------- */
97 
98  if (z[1] < z[0]) {swap(z[1],z[0]);}
99  else if (z[1] > z[3]) {swap(z[1],z[3]);}
100 
101 
102  if (z[2] < z[0]) {
103  swap(z[2],z[0]);
104  swap(z[2],z[1]);
105  }else if (z[2] < z[1]){
106  swap(z[2],z[1]);
107  }else if (z[2] > z[3]){
108  swap(z[2],z[3]);
109  }
110 
111 /*
112  for (j = 1; j < 4; j++){
113  f = z[j];
114  n = j - 1;
115  while(n >= 0 && z[n] > f) {
116  z[n+1] = z[n];
117  n--;
118  }
119  z[n+1] = f;
120  }
121 */
122 
123  /* ----------------------------------------------
124  verify that cmax and cmin satisfy original
125  equation
126  ---------------------------------------------- */
127 
128  for (n = 0; n < 4; n++){
129  s = e + z[n]*(d + z[n]*(c + z[n]*(b + z[n])));
130  if (s != s) {
131 // print ("! QuarticSolve: NaN found.\n");
132  return 2;
133  }
134  if (fabs(s) > 1.e-6) {
135 // print ("! QuarticSolve: solution does not satisfy f(z) = 0; f(z) = %12.6e\n",s);
136  return 3;
137  }
138  }
139 
140  return(0);
141 /*
142  printf (" z: %f ; %f ; %f ; %f\n",z[0], z[1], z[2], z[3]);
143  */
144 }
145 #undef swap
146 /* ********************************************************************* */
147 int CubicSolve (double b, double c, double d, double z[])
148 /*!
149  * Solve a cubic equation in the form
150  * \f[
151  * z^3 + bz^2 + cz + d = 0
152  * \f]
153  * For its purpose, it is assumed that \b ALL roots are double.
154  * This makes things faster.
155  *
156  * \param [in] b coefficient of the cubic
157  * \param [in] c coefficient of the cubic
158  * \param [in] d coefficient of the cubic
159  * \param [out] z vector containing the roots of the cubic.
160  * Roots should be sorted in increasing order.
161  *
162  * \b Reference: http://www.1728.com/cubic2.htm
163  *
164  * \return Return 0 on success.
165  *
166  *********************************************************************** */
167 {
168  double b2, g2;
169  double f, g, h;
170  double i, i2, j, k, m, n, p;
171  static double one_3 = 1.0/3.0, one_27=1.0/27.0;
172 
173  b2 = b*b;
174 
175 /* ----------------------------------------------
176  the expression for f should be
177  f = c - b*b/3.0; however, to avoid negative
178  round-off making h > 0.0 or g^2/4 - h < 0.0
179  we let c --> c(1- 1.1e-16)
180  ---------------------------------------------- */
181 
182  f = c*(1.0 - 1.e-16) - b2*one_3;
183  g = b*(2.0*b2 - 9.0*c)*one_27 + d;
184  g2 = g*g;
185  i2 = -f*f*f*one_27;
186  h = g2*0.25 - i2;
187 
188 /* --------------------------------------------
189  double roots are possible only when
190 
191  h <= 0
192  -------------------------------------------- */
193 
194  if (h > 1.e-12){
195 // printf ("Only one double root (%12.6e)!\n", h);
196  }
197  if (i2 < 0.0){
198 /*
199  printf ("i2 < 0.0 %12.6e\n",i2);
200  return(1);
201 */
202  i2 = 0.0;
203  }
204 
205 /* --------------------------------------
206  i^2 must be >= g2*0.25
207  -------------------------------------- */
208 
209  i = sqrt(i2); /* > 0 */
210  j = pow(i, one_3); /* > 0 */
211  k = -0.5*g/i;
212 
213 /* this is to prevent unpleseant situation
214  where both g and i are close to zero */
215 
216  k = (k < -1.0 ? -1.0:k);
217  k = (k > 1.0 ? 1.0:k);
218 
219  k = acos(k)*one_3; /* pi/3 < k < 0 */
220 
221  m = cos(k); /* > 0 */
222  n = sqrt(3.0)*sin(k); /* > 0 */
223  p = -b*one_3;
224 
225  z[0] = -j*(m + n) + p;
226  z[1] = -j*(m - n) + p;
227  z[2] = 2.0*j*m + p;
228 
229 /* ------------------------------------------------------
230  Since j, m, n > 0, it should follow that from
231 
232  z0 = -jm - jn + p
233  z1 = -jm + jn + p
234  z2 = 2jm + p
235 
236  z2 is the greatest of the roots, while z0 is the
237  smallest one.
238  ------------------------------------------------------ */
239 
240  return(0);
241 }
242 
243 
244 
245 
246 /* ********************************************************************* */
247 int QuarticSolve2 (double b, double c, double d, double e, double *z)
248 /*!
249  * Solve a quartic equation in the form
250  * \f[
251  * z^4 + bz^3 + cz^2 + dz + e = 0
252  * \f]
253  * using Durand-Kerner method.
254  *
255  * \param [in] b coefficient of the quartic
256  * \param [in] c coefficient of the quartic
257  * \param [in] d coefficient of the quartic
258  * \param [in] e coefficient of the quartic
259  * \param [out] z vector containing the
260  * (double) roots of the quartic
261  *
262  * \b Reference:
263  *
264  *
265  * \return Return 0 on success, 1 if cubic solver fails, 2 if NaN has
266  * been found and 3 if quartic is not satisfied.
267  *
268  *********************************************************************** */
269 #define ZQUARTIC(x) (ez + (x)*(dz + (x)*(cz + (x)*(bz + (x)))))
270 {
271  int k;
272  double complex bz = b;
273  double complex cz = c;
274  double complex dz = d;
275  double complex ez = e;
276  double complex p, q, r, s;
277  double complex dp, dq, dr, ds;
278  double acc = 1.e-5, err;
279 
280  p = -1.0 + 0.000012*_Complex_I;
281  q = -0.25 + 0.00002*_Complex_I;
282  r = 0.25 + 0.00002*_Complex_I;
283  s = 1.0 - 0.000011*_Complex_I;
284 
285  for (k = 0; k < 4096; k++){
286 
287  dp = ZQUARTIC(p)/( (p - q)*(p - r)*(p - s) );
288  p -= dp;
289 
290  dq = ZQUARTIC(q)/( (q - p)*(q - r)*(q - s) );
291  q -= dq;
292 
293  dr = ZQUARTIC(r)/( (r - p)*(r - q)*(r - s) );
294  r -= dr;
295 
296  ds = ZQUARTIC(s)/( (s - p)*(s - q)*(s - r) );
297  s -= ds;
298 
299  err = MAX(cabs(dp), cabs(dq));
300  err = MAX(err, cabs(dr));
301  err = MAX(err, cabs(ds));
302 
303  if (err < acc) break;
304 
305  }
306 /*
307  printf ("Solution = %12.6e %12.6e %12.6e %12.6e\n",
308  creal(p), creal(q), creal(r), creal(s));
309  printf ("Number of iterations = %d\n",k);
310  printf ("Residual: %8.3e, %8.3e, %8.3e, %8.3e\n",cabs(dp),cabs(dq),cabs(dr),cabs(ds));
311 */
312 
313  z[0] = creal(p);
314  z[1] = creal(q);
315  z[2] = creal(r);
316  z[3] = creal(s);
317 
318 double zmin, zmax;
319 
320  zmax = MAX(z[0],z[1]);
321  zmax = MAX(zmax,z[2]);
322  zmax = MAX(zmax,z[3]);
323 
324  zmin = MIN(z[0],z[1]);
325  zmin = MIN(zmin,z[2]);
326  zmin = MIN(zmin,z[3]);
327  z[0] = zmin;
328  z[3] = zmax;
329 
330 }
#define MAX(a, b)
Definition: macros.h:101
static int n
Definition: analysis.c:3
int CubicSolve(double b, double c, double d, double z[])
Definition: quartic.old.c:147
#define swap(x, y)
Definition: quartic.old.c:18
#define MIN(a, b)
Definition: macros.h:104
int j
Definition: analysis.c:2
int k
Definition: analysis.c:2
tuple c
Definition: menu.py:375
#define s
PLUTO main header file.
int QuarticSolve(double b, double c, double d, double e, double *z)
Definition: quartic.old.c:21
int i
Definition: analysis.c:2
#define ZQUARTIC(x)
static Runtime q
int QuarticSolve2(double b, double c, double d, double e, double *z)
Definition: quartic.old.c:247