00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <math.h>
00031 #include <gsl/gsl_math.h>
00032 #include <gsl/gsl_complex.h>
00033 #include <gsl/gsl_complex_math.h>
00034 #include <gsl/gsl_poly.h>
00035
00036 #define SWAP(a,b) do { gsl_complex tmp = b ; b = a ; a = tmp ; } while(0)
00037
00038 int
00039 gsl_poly_complex_solve_quartic (double a, double b, double c, double d,
00040 gsl_complex * z0, gsl_complex * z1,
00041 gsl_complex * z2, gsl_complex * z3)
00042 {
00043 gsl_complex i, zarr[4], w1, w2, w3;
00044 double r4 = 1.0 / 4.0;
00045 double q2 = 1.0 / 2.0, q4 = 1.0 / 4.0, q8 = 1.0 / 8.0;
00046 double q1 = 3.0 / 8.0, q3 = 3.0 / 16.0;
00047 double u[3], v[3], v1, v2, disc;
00048 double aa, pp, qq, rr, rc, sc, tc, q, h;
00049 int k1 = 0, k2 = 0, mt;
00050
00051 GSL_SET_COMPLEX (&i, 0.0, 1.0);
00052 GSL_SET_COMPLEX (&zarr[0], 0.0, 0.0);
00053 GSL_SET_COMPLEX (&zarr[1], 0.0, 0.0);
00054 GSL_SET_COMPLEX (&zarr[2], 0.0, 0.0);
00055 GSL_SET_COMPLEX (&zarr[3], 0.0, 0.0);
00056 GSL_SET_COMPLEX (&w1, 0.0, 0.0);
00057 GSL_SET_COMPLEX (&w2, 0.0, 0.0);
00058 GSL_SET_COMPLEX (&w3, 0.0, 0.0);
00059
00060
00061
00062 if (0 == b && 0 == c)
00063 {
00064 if (0 == d)
00065 {
00066 if (a > 0)
00067 {
00068 GSL_SET_COMPLEX (z0, -a, 0.0);
00069 GSL_SET_COMPLEX (z1, 0.0, 0.0);
00070 GSL_SET_COMPLEX (z2, 0.0, 0.0);
00071 GSL_SET_COMPLEX (z3, 0.0, 0.0);
00072 }
00073 else
00074 {
00075 GSL_SET_COMPLEX (z0, 0.0, 0.0);
00076 GSL_SET_COMPLEX (z1, 0.0, 0.0);
00077 GSL_SET_COMPLEX (z2, 0.0, 0.0);
00078 GSL_SET_COMPLEX (z3, -a, 0.0);
00079 }
00080 return 4;
00081 }
00082 else if (0 == a)
00083 {
00084 if (d > 0)
00085 {
00086 double sqrt_d = sqrt (d);
00087 gsl_complex i_sqrt_d = gsl_complex_mul_real (i, sqrt_d);
00088 gsl_complex minus_i = gsl_complex_conjugate (i);
00089 *z3 = gsl_complex_sqrt (i_sqrt_d);
00090 *z2 = gsl_complex_mul (minus_i, *z3);
00091 *z1 = gsl_complex_negative (*z2);
00092 *z0 = gsl_complex_negative (*z3);
00093 }
00094 else
00095 {
00096 double sqrt_abs_d = sqrt (-d);
00097 *z3 = gsl_complex_sqrt_real (sqrt_abs_d);
00098 *z2 = gsl_complex_mul (i, *z3);
00099 *z1 = gsl_complex_negative (*z2);
00100 *z0 = gsl_complex_negative (*z3);
00101 }
00102 return 4;
00103 }
00104 }
00105
00106 if (0.0 == c && 0.0 == d)
00107 {
00108 disc = (a * a - 4.0 * b);
00109 if (disc < 0.0)
00110 {
00111 mt = 3;
00112 }
00113 else
00114 {
00115 mt = 1;
00116 }
00117 *z0 = zarr[0];
00118 *z1 = zarr[0];
00119 gsl_poly_complex_solve_quadratic (1.0, a, b, z2, z3);
00120 }
00121 else
00122 {
00123
00124
00125 aa = a * a;
00126 pp = b - q1 * aa;
00127 qq = c - q2 * a * (b - q4 * aa);
00128 rr = d - q4 * (a * c - q4 * aa * (b - q3 * aa));
00129 rc = q2 * pp;
00130 sc = q4 * (q4 * pp * pp - rr);
00131 tc = -(q8 * qq * q8 * qq);
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 {
00142 double qcub = (rc * rc - 3 * sc);
00143 double rcub = (2 * rc * rc * rc - 9 * rc * sc + 27 * tc);
00144
00145 double Q = qcub / 9;
00146 double R = rcub / 54;
00147
00148 double Q3 = Q * Q * Q;
00149 double R2 = R * R;
00150
00151 disc = R2 - Q3;
00152
00153
00154
00155
00156
00157
00158
00159 if (0 == R && 0 == Q)
00160 {
00161 u[0] = -rc / 3;
00162 u[1] = -rc / 3;
00163 u[2] = -rc / 3;
00164 }
00165 else if (R2 == Q3)
00166 {
00167 double sqrtQ = sqrt (Q);
00168 if (R > 0)
00169 {
00170 u[0] = -2 * sqrtQ - rc / 3;
00171 u[1] = sqrtQ - rc / 3;
00172 u[2] = sqrtQ - rc / 3;
00173 }
00174 else
00175 {
00176 u[0] = -sqrtQ - rc / 3;
00177 u[1] = -sqrtQ - rc / 3;
00178 u[2] = 2 * sqrtQ - rc / 3;
00179 }
00180 }
00181 else if ( R2 < Q3)
00182 {
00183 double sqrtQ = sqrt (Q);
00184 double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ;
00185 double ctheta = R / sqrtQ3;
00186 double theta = 0;
00187
00188 if ( fabs(ctheta) < 1.0 )
00189 theta = acos( ctheta);
00190 else if ( ctheta <= -1.0)
00191 theta = M_PI;
00192
00193 double norm = -2 * sqrtQ;
00194
00195 u[0] = norm * cos (theta / 3) - rc / 3;
00196 u[1] = norm * cos ((theta + 2.0 * M_PI) / 3) - rc / 3;
00197 u[2] = norm * cos ((theta - 2.0 * M_PI) / 3) - rc / 3;
00198 }
00199 else
00200 {
00201 double sgnR = (R >= 0 ? 1 : -1);
00202 double modR = fabs (R);
00203 double sqrt_disc = sqrt (disc);
00204 double A = -sgnR * pow (modR + sqrt_disc, 1.0 / 3.0);
00205 double B = Q / A;
00206
00207 double mod_diffAB = fabs (A - B);
00208 u[0] = A + B - rc / 3;
00209 u[1] = -0.5 * (A + B) - rc / 3;
00210 u[2] = -(sqrt (3.0) / 2.0) * mod_diffAB;
00211 }
00212 }
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 if (0 >= disc)
00224 {
00225 mt = 2;
00226 v[0] = fabs (u[0]);
00227 v[1] = fabs (u[1]);
00228 v[2] = fabs (u[2]);
00229
00230 v1 = GSL_MAX (GSL_MAX (v[0], v[1]), v[2]);
00231 if (v1 == v[0])
00232 {
00233 k1 = 0;
00234 v2 = GSL_MAX (v[1], v[2]);
00235 }
00236 else if (v1 == v[1])
00237 {
00238 k1 = 1;
00239 v2 = GSL_MAX (v[0], v[2]);
00240 }
00241 else
00242 {
00243 k1 = 2;
00244 v2 = GSL_MAX (v[0], v[1]);
00245 }
00246
00247 if (v2 == v[0])
00248 {
00249 k2 = 0;
00250 }
00251 else if (v2 == v[1])
00252 {
00253 k2 = 1;
00254 }
00255 else
00256 {
00257 k2 = 2;
00258 }
00259 w1 = gsl_complex_sqrt_real (u[k1]);
00260 w2 = gsl_complex_sqrt_real (u[k2]);
00261 }
00262 else
00263 {
00264 mt = 3;
00265 GSL_SET_COMPLEX (&w1, u[1], u[2]);
00266 GSL_SET_COMPLEX (&w2, u[1], -u[2]);
00267 w1 = gsl_complex_sqrt (w1);
00268 w2 = gsl_complex_sqrt (w2);
00269 }
00270
00271
00272 q = qq;
00273 gsl_complex prod_w = gsl_complex_mul (w1, w2);
00274
00275
00276
00277
00278 double mod_prod_w = gsl_complex_abs (prod_w);
00279 if (0.0 != mod_prod_w)
00280 {
00281 gsl_complex inv_prod_w = gsl_complex_inverse (prod_w);
00282 w3 = gsl_complex_mul_real (inv_prod_w, -q / 8.0);
00283 }
00284
00285 h = r4 * a;
00286 gsl_complex sum_w12 = gsl_complex_add (w1, w2);
00287 gsl_complex neg_sum_w12 = gsl_complex_negative (sum_w12);
00288 gsl_complex sum_w123 = gsl_complex_add (sum_w12, w3);
00289 gsl_complex neg_sum_w123 = gsl_complex_add (neg_sum_w12, w3);
00290
00291 gsl_complex diff_w12 = gsl_complex_sub (w2, w1);
00292 gsl_complex neg_diff_w12 = gsl_complex_negative (diff_w12);
00293 gsl_complex diff_w123 = gsl_complex_sub (diff_w12, w3);
00294 gsl_complex neg_diff_w123 = gsl_complex_sub (neg_diff_w12, w3);
00295
00296 zarr[0] = gsl_complex_add_real (sum_w123, -h);
00297 zarr[1] = gsl_complex_add_real (neg_sum_w123, -h);
00298 zarr[2] = gsl_complex_add_real (diff_w123, -h);
00299 zarr[3] = gsl_complex_add_real (neg_diff_w123, -h);
00300
00301
00302 if (2 == mt)
00303 {
00304 if (u[k1] >= 0 && u[k2] >= 0)
00305 {
00306 mt = 1;
00307 GSL_SET_COMPLEX (z0, GSL_REAL (zarr[0]), 0.0);
00308 GSL_SET_COMPLEX (z1, GSL_REAL (zarr[1]), 0.0);
00309 GSL_SET_COMPLEX (z2, GSL_REAL (zarr[2]), 0.0);
00310 GSL_SET_COMPLEX (z3, GSL_REAL (zarr[3]), 0.0);
00311 }
00312 else if (u[k1] >= 0 && u[k2] < 0)
00313 {
00314 *z0 = zarr[0];
00315 *z1 = zarr[3];
00316 *z2 = zarr[2];
00317 *z3 = zarr[1];
00318 }
00319 else if (u[k1] < 0 && u[k2] >= 0)
00320 {
00321 *z0 = zarr[0];
00322 *z1 = zarr[2];
00323 *z2 = zarr[3];
00324 *z3 = zarr[1];
00325 }
00326 else if (u[k1] < 0 && u[k2] < 0)
00327 {
00328 *z0 = zarr[0];
00329 *z1 = zarr[1];
00330 *z2 = zarr[3];
00331 *z3 = zarr[2];
00332 }
00333 }
00334 else if (3 == mt)
00335 {
00336 GSL_SET_COMPLEX (z0, GSL_REAL (zarr[0]), 0.0);
00337 GSL_SET_COMPLEX (z1, GSL_REAL (zarr[1]), 0.0);
00338 *z2 = zarr[3];
00339 *z3 = zarr[2];
00340 }
00341 }
00342
00343
00344
00345
00346
00347
00348 if (1 == mt)
00349 {
00350
00351 if (GSL_REAL (*z0) > GSL_REAL (*z1)) SWAP (*z0, *z1);
00352 if (GSL_REAL (*z0) > GSL_REAL (*z2)) SWAP (*z0, *z2);
00353 if (GSL_REAL (*z0) > GSL_REAL (*z3)) SWAP (*z0, *z3);
00354
00355 if (GSL_REAL (*z1) > GSL_REAL (*z2)) SWAP (*z1, *z2);
00356 if (GSL_REAL (*z2) > GSL_REAL (*z3))
00357 {
00358 SWAP (*z2, *z3);
00359 if (GSL_REAL (*z1) > GSL_REAL (*z2)) SWAP (*z1, *z2);
00360 }
00361 }
00362 else if (2 == mt)
00363 {
00364
00365
00366 if (GSL_REAL (*z0) > GSL_REAL (*z2))
00367 {
00368 SWAP (*z0, *z2);
00369 SWAP (*z1, *z3);
00370 }
00371
00372 if (GSL_IMAG (*z0) > GSL_IMAG (*z1)) SWAP (*z0, *z1);
00373 if (GSL_IMAG (*z2) > GSL_IMAG (*z3)) SWAP (*z2, *z3);
00374 }
00375 else
00376 {
00377
00378
00379
00380 if (GSL_IMAG (*z2) > GSL_IMAG (*z3)) SWAP (*z2, *z3);
00381
00382
00383 if (GSL_REAL (*z0) > GSL_REAL (*z1)) SWAP (*z0, *z1);
00384 if (GSL_REAL (*z1) > GSL_REAL (*z2))
00385 {
00386 if (GSL_REAL (*z0) > GSL_REAL (*z2))
00387 {
00388 SWAP (*z0, *z2);
00389 SWAP (*z1, *z3);
00390 }
00391 else
00392 {
00393 SWAP (*z1, *z2);
00394 SWAP (*z2, *z3);
00395 }
00396 }
00397 }
00398
00399 return 4;
00400 }
00401