zsolve_cubic.cxx

Go to the documentation of this file.
00001 /* poly/zsolve_cubic.c
00002  * 
00003  * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Brian Gough
00004  * 
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 3 of the License, or (at
00008  * your option) any later version.
00009  * 
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * General Public License for more details.
00014  * 
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  */
00019 
00020 /* zsolve_cubic.c - finds the complex roots of x^3 + a x^2 + b x + c = 0 */
00021 
00022 //#include <config.h>
00023 #include <math.h>
00024 #include <gsl/gsl_math.h>
00025 #include <gsl/gsl_complex.h>
00026 #include <gsl/gsl_poly.h>
00027 
00028 #define SWAP(a,b) do { double tmp = b ; b = a ; a = tmp ; } while(0)
00029 
00030 int
00031 gsl_poly_complex_solve_cubic (double a, double b, double c, 
00032                               gsl_complex *z0, gsl_complex *z1, 
00033                               gsl_complex *z2)
00034 {
00035   double q = (a * a - 3 * b);
00036   double r = (2 * a * a * a - 9 * a * b + 27 * c);
00037 
00038   double Q = q / 9;
00039   double R = r / 54;
00040 
00041   double Q3 = Q * Q * Q;
00042   double R2 = R * R;
00043 
00044 //  double CR2 = 729 * r * r;
00045 //  double CQ3 = 2916 * q * q * q;
00046 
00047   if (R == 0 && Q == 0)
00048     {
00049       GSL_REAL (*z0) = -a / 3;
00050       GSL_IMAG (*z0) = 0;
00051       GSL_REAL (*z1) = -a / 3;
00052       GSL_IMAG (*z1) = 0;
00053       GSL_REAL (*z2) = -a / 3;
00054       GSL_IMAG (*z2) = 0;
00055       return 3;
00056     }
00057   else if (R2 == Q3) 
00058     {
00059       /* this test is actually R2 == Q3, written in a form suitable
00060          for exact computation with integers */
00061 
00062       /* Due to finite precision some double roots may be missed, and
00063          will be considered to be a pair of complex roots z = x +/-
00064          epsilon i close to the real axis. */
00065 
00066       double sqrtQ = sqrt (Q);
00067 
00068       if (R > 0)
00069         {
00070           GSL_REAL (*z0) = -2 * sqrtQ - a / 3;
00071           GSL_IMAG (*z0) = 0;
00072           GSL_REAL (*z1) = sqrtQ - a / 3;
00073           GSL_IMAG (*z1) = 0;
00074           GSL_REAL (*z2) = sqrtQ - a / 3;
00075           GSL_IMAG (*z2) = 0;
00076         }
00077       else
00078         {
00079           GSL_REAL (*z0) = -sqrtQ - a / 3;
00080           GSL_IMAG (*z0) = 0;
00081           GSL_REAL (*z1) = -sqrtQ - a / 3;
00082           GSL_IMAG (*z1) = 0;
00083           GSL_REAL (*z2) = 2 * sqrtQ - a / 3;
00084           GSL_IMAG (*z2) = 0;
00085         }
00086       return 3;
00087     }
00088   else if (R2 < Q3)  /* equivalent to R2 < Q3 */
00089     {
00090       double sqrtQ = sqrt (Q);
00091       double sqrtQ3 = sqrtQ * sqrtQ * sqrtQ;
00092       double ctheta = R / sqrtQ3;
00093       double theta = 0; 
00094       if ( ctheta <= -1.0) 
00095          theta = M_PI;
00096       else if ( ctheta < 1.0) 
00097          theta = acos (R / sqrtQ3);
00098       
00099       double norm = -2 * sqrtQ;
00100       double r0 = norm * cos (theta / 3) - a / 3;
00101       double r1 = norm * cos ((theta + 2.0 * M_PI) / 3) - a / 3;
00102       double r2 = norm * cos ((theta - 2.0 * M_PI) / 3) - a / 3;
00103 
00104       /* Sort r0, r1, r2 into increasing order */
00105 
00106       if (r0 > r1)
00107         SWAP (r0, r1);
00108 
00109       if (r1 > r2)
00110         {
00111           SWAP (r1, r2);
00112 
00113           if (r0 > r1)
00114             SWAP (r0, r1);
00115         }
00116 
00117       GSL_REAL (*z0) = r0;
00118       GSL_IMAG (*z0) = 0;
00119 
00120       GSL_REAL (*z1) = r1;
00121       GSL_IMAG (*z1) = 0;
00122 
00123       GSL_REAL (*z2) = r2;
00124       GSL_IMAG (*z2) = 0;
00125 
00126       return 3;
00127     }
00128   else
00129     {
00130       double sgnR = (R >= 0 ? 1 : -1);
00131       double A = -sgnR * pow (fabs (R) + sqrt (R2 - Q3), 1.0 / 3.0);
00132       double B = Q / A;
00133 
00134       if (A + B < 0)
00135         {
00136           GSL_REAL (*z0) = A + B - a / 3;
00137           GSL_IMAG (*z0) = 0;
00138 
00139           GSL_REAL (*z1) = -0.5 * (A + B) - a / 3;
00140           GSL_IMAG (*z1) = -(sqrt (3.0) / 2.0) * fabs(A - B);
00141 
00142           GSL_REAL (*z2) = -0.5 * (A + B) - a / 3;
00143           GSL_IMAG (*z2) = (sqrt (3.0) / 2.0) * fabs(A - B);
00144         }
00145       else
00146         {
00147           GSL_REAL (*z0) = -0.5 * (A + B) - a / 3;
00148           GSL_IMAG (*z0) = -(sqrt (3.0) / 2.0) * fabs(A - B);
00149 
00150           GSL_REAL (*z1) = -0.5 * (A + B) - a / 3;
00151           GSL_IMAG (*z1) = (sqrt (3.0) / 2.0) * fabs(A - B);
00152 
00153           GSL_REAL (*z2) = A + B - a / 3;
00154           GSL_IMAG (*z2) = 0;
00155         }
00156 
00157       return 3;
00158     }
00159 }

Generated on Tue Jul 5 14:34:58 2011 for ROOT_528-00b_version by  doxygen 1.5.1