poly34.cpp
Go to the documentation of this file.
00001 // poly.cpp : solution of cubic and quartic equation
00002 // (c) Khashin S.I. http://math.ivanovo.ac.ru/dalgebra/Khashin/index.html
00003 // khash2 (at) gmail.com
00004 //
00005 #include <math.h>
00006 
00007 #include "MathHelpers/Resectionsolver/poly34.h"     // solution of cubic and quartic equation
00008 #define TwoPi  6.28318530717958648
00009 const double eps=1e-14;
00010 //---------------------------------------------------------------------------
00011 // x - array of size 3
00012 // In case 3 real roots: => x[0], x[1], x[2], return 3
00013 //         2 real roots: x[0], x[1],          return 2
00014 //         1 real root : x[0], x[1] � i*x[2], return 1
00015 int SolveP3(double *x,double a,double b,double c) {     // solve cubic equation x^3 + a*x^2 + b*x + c
00016     double a2 = a*a;
00017     double q  = (a2 - 3*b)/9;
00018     double r  = (a*(2*a2-9*b) + 27*c)/54;
00019     double r2 = r*r;
00020     double q3 = q*q*q;
00021     double A,B;
00022     if(r2<q3) {
00023         double t=r/sqrt(q3);
00024         if( t<-1) t=-1;
00025         if( t> 1) t= 1;
00026         t=acos(t);
00027         a/=3; q=-2*sqrt(q);
00028         x[0]=q*cos(t/3)-a;
00029         x[1]=q*cos((t+TwoPi)/3)-a;
00030         x[2]=q*cos((t-TwoPi)/3)-a;
00031         return(3);
00032     } else {
00033         A =-pow(fabs(r)+sqrt(r2-q3),1./3);
00034         if( r<0 ) A=-A;
00035         B = A==0 ? 0 : q/A;
00036 
00037         a/=3;
00038         x[0] =(A+B)-a;
00039         x[1] =-0.5*(A+B)-a;
00040         x[2] = 0.5*sqrt(3.)*(A-B);
00041         if(fabs(x[2])<eps) { x[2]=x[1]; return(2); }
00042         return(1);
00043     }
00044 }// SolveP3(double *x,double a,double b,double c) {
00045 //---------------------------------------------------------------------------
00046 // a>=0!
00047 void  CSqrt( double x, double y, double &a, double &b) // returns:  a+i*s = sqrt(x+i*y)
00048 {
00049     double r  = sqrt(x*x+y*y);
00050     if( y==0 ) {
00051         r = sqrt(r);
00052         if(x>=0) { a=r; b=0; } else { a=0; b=r; }
00053     } else {            // y != 0
00054         a = sqrt(0.5*(x+r));
00055         b = 0.5*y/a;
00056     }
00057 }
00058 //---------------------------------------------------------------------------
00059 int   SolveP4Bi(double *x, double b, double d)  // solve equation x^4 + b*x^2 + d = 0
00060 {
00061     double D = b*b-4*d;
00062     if( D>=0 )
00063     {
00064         double sD = sqrt(D);
00065         double x1 = (-b+sD)/2;
00066         double x2 = (-b-sD)/2;  // x2 <= x1
00067         if( x2>=0 )                             // 0 <= x2 <= x1, 4 real roots
00068         {
00069             double sx1 = sqrt(x1);
00070             double sx2 = sqrt(x2);
00071             x[0] = -sx1;
00072             x[1] =  sx1;
00073             x[2] = -sx2;
00074             x[3] =  sx2;
00075             return 4;
00076         }
00077         if( x1 < 0 )                            // x2 <= x1 < 0, two pair of imaginary roots
00078         {
00079             double sx1 = sqrt(-x1);
00080             double sx2 = sqrt(-x2);
00081             x[0] =    0;
00082             x[1] =  sx1;
00083             x[2] =    0;
00084             x[3] =  sx2;
00085             return 0;
00086         }
00087         // now x2 < 0 <= x1 , two real roots and one pair of imginary root
00088             double sx1 = sqrt( x1);
00089             double sx2 = sqrt(-x2);
00090             x[0] = -sx1;
00091             x[1] =  sx1;
00092             x[2] =    0;
00093             x[3] =  sx2;
00094             return 2;
00095     } else { // if( D < 0 ), two pair of compex roots
00096         double sD2 = 0.5*sqrt(-D);
00097         CSqrt(-0.5*b, sD2, x[0],x[1]);
00098         CSqrt(-0.5*b,-sD2, x[2],x[3]);
00099         return 0;
00100     } // if( D>=0 )
00101 } // SolveP4Bi(double *x, double b, double d)   // solve equation x^4 + b*x^2 d
00102 //---------------------------------------------------------------------------
00103 #define SWAP(a,b) { t=b; b=a; a=t; }
00104 static void  dblSort3( double &a, double &b, double &c) // make: a <= b <= c
00105 {
00106     double t;
00107     if( a>b ) SWAP(a,b);        // now a<=b
00108     if( c<b ) {
00109         SWAP(b,c);                      // now a<=b, b<=c
00110         if( a>b ) SWAP(a,b);// now a<=b
00111     }
00112 }
00113 //---------------------------------------------------------------------------
00114 int   SolveP4De(double *x, double b, double c, double d)        // solve equation x^4 + b*x^2 + c*x + d
00115 {
00116     //if( c==0 ) return SolveP4Bi(x,b,d); // After that, c!=0
00117     if( fabs(c)<1e-14*(fabs(b)+fabs(d)) ) return SolveP4Bi(x,b,d); // After that, c!=0
00118 
00119     int res3 = SolveP3( x, 2*b, b*b-4*d, -c*c); // solve resolvent
00120     // by Viet theorem:  x1*x2*x3=-c*c not equals to 0, so x1!=0, x2!=0, x3!=0
00121     if( res3>1 )        // 3 real roots,
00122     {
00123         dblSort3(x[0], x[1], x[2]);     // sort roots to x[0] <= x[1] <= x[2]
00124         // Note: x[0]*x[1]*x[2]= c*c > 0
00125         if( x[0] > 0) // all roots are positive
00126         {
00127             double sz1 = sqrt(x[0]);
00128             double sz2 = sqrt(x[1]);
00129             double sz3 = sqrt(x[2]);
00130             // Note: sz1*sz2*sz3= -c (and not equal to 0)
00131             if( c>0 )
00132             {
00133                 x[0] = (-sz1 -sz2 -sz3)/2;
00134                 x[1] = (-sz1 +sz2 +sz3)/2;
00135                 x[2] = (+sz1 -sz2 +sz3)/2;
00136                 x[3] = (+sz1 +sz2 -sz3)/2;
00137                 return 4;
00138             }
00139             // now: c<0
00140             x[0] = (-sz1 -sz2 +sz3)/2;
00141             x[1] = (-sz1 +sz2 -sz3)/2;
00142             x[2] = (+sz1 -sz2 -sz3)/2;
00143             x[3] = (+sz1 +sz2 +sz3)/2;
00144             return 4;
00145         } // if( x[0] > 0) // all roots are positive
00146         // now x[0] <= x[1] < 0, x[2] > 0
00147         // two pair of comlex roots
00148         double sz1 = sqrt(-x[0]);
00149         double sz2 = sqrt(-x[1]);
00150         double sz3 = sqrt( x[2]);
00151 
00152         if( c>0 )       // sign = -1
00153         {
00154             x[0] = -sz3/2;
00155             x[1] = ( sz1 -sz2)/2;               // x[0]�i*x[1]
00156             x[2] =  sz3/2;
00157             x[3] = (-sz1 -sz2)/2;               // x[2]�i*x[3]
00158             return 0;
00159         }
00160         // now: c<0 , sign = +1
00161         x[0] =   sz3/2;
00162         x[1] = (-sz1 +sz2)/2;
00163         x[2] =  -sz3/2;
00164         x[3] = ( sz1 +sz2)/2;
00165         return 0;
00166     } // if( res3>1 )   // 3 real roots,
00167     // now resoventa have 1 real and pair of compex roots
00168     // x[0] - real root, and x[0]>0,
00169     // x[1]�i*x[2] - complex roots,
00170     double sz1 = sqrt(x[0]);
00171     double szr, szi;
00172     CSqrt(x[1], x[2], szr, szi);  // (szr+i*szi)^2 = x[1]+i*x[2]
00173     if( c>0 )   // sign = -1
00174     {
00175         x[0] = -sz1/2-szr;                      // 1st real root
00176         x[1] = -sz1/2+szr;                      // 2nd real root
00177         x[2] = sz1/2;
00178         x[3] = szi;
00179         return 2;
00180     }
00181     // now: c<0 , sign = +1
00182     x[0] = sz1/2-szr;                   // 1st real root
00183     x[1] = sz1/2+szr;                   // 2nd real root
00184     x[2] = -sz1/2;
00185     x[3] = szi;
00186     return 2;
00187 } // SolveP4De(double *x, double b, double c, double d) // solve equation x^4 + b*x^2 + c*x + d
00188 //-----------------------------------------------------------------------------
00189 double N4Step(double x, double a,double b,double c,double d)    // one Newton step for x^4 + a*x^3 + b*x^2 + c*x + d
00190 {
00191     double fxs= ((4*x+3*a)*x+2*b)*x+c;  // f'(x)
00192     if( fxs==0 ) return 1e99;
00193     double fx = (((x+a)*x+b)*x+c)*x+d;  // f(x)
00194     return x - fx/fxs;
00195 }
00196 //-----------------------------------------------------------------------------
00197 // x - array of size 4
00198 // return 4: 4 real roots x[0], x[1], x[2], x[3], possible multiple roots
00199 // return 2: 2 real roots x[0], x[1] and complex x[2]�i*x[3],
00200 // return 0: two pair of complex roots: x[0]�i*x[1],  x[2]�i*x[3],
00201 int   SolveP4(double *x,double a,double b,double c,double d) {  // solve equation x^4 + a*x^3 + b*x^2 + c*x + d by Dekart-Euler method
00202     // move to a=0:
00203     double d1 = d + 0.25*a*( 0.25*b*a - 3./64*a*a*a - c);
00204     double c1 = c + 0.5*a*(0.25*a*a - b);
00205     double b1 = b - 0.375*a*a;
00206     int res = SolveP4De( x, b1, c1, d1);
00207     if( res==4) { x[0]-= a/4; x[1]-= a/4; x[2]-= a/4; x[3]-= a/4; }
00208     else if (res==2) { x[0]-= a/4; x[1]-= a/4; x[2]-= a/4; }
00209     else             { x[0]-= a/4; x[2]-= a/4; }
00210     // one Newton step for each real root:
00211     if( res>0 )
00212     {
00213         x[0] = N4Step(x[0], a,b,c,d);
00214         x[1] = N4Step(x[1], a,b,c,d);
00215     }
00216     if( res>2 )
00217     {
00218         x[2] = N4Step(x[2], a,b,c,d);
00219         x[3] = N4Step(x[3], a,b,c,d);
00220     }
00221     return res;
00222 }
00223 //-----------------------------------------------------------------------------
00224 #define F5(t) (((((t+a)*t+b)*t+c)*t+d)*t+e)
00225 //-----------------------------------------------------------------------------
00226 double SolveP5_1(double a,double b,double c,double d,double e)  // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
00227 {
00228     int cnt;
00229     if( fabs(e)<eps ) return 0;
00230 
00231     double brd =  fabs(a);                      // brd - border of real roots
00232     if( fabs(b)>brd ) brd = fabs(b);
00233     if( fabs(c)>brd ) brd = fabs(c);
00234     if( fabs(d)>brd ) brd = fabs(d);
00235     if( fabs(e)>brd ) brd = fabs(e);
00236     brd++;                                                      // brd - border of real roots
00237 
00238     double x0, f0;                                      // less, than root
00239     double x1, f1;                                      // greater, than root
00240     double x2, f2, f2s;                         // next values, f(x2), f'(x2)
00241     double dx = 0.0;
00242 
00243     if( e<0 ) { x0 =   0; x1 = brd; f0=e; f1=F5(x1); x2 = 0.01*brd; }
00244     else          { x0 =-brd; x1 =   0; f0=F5(x0); f1=e; x2 =-0.01*brd; }
00245 
00246     if( fabs(f0)<eps ) return x0;
00247     if( fabs(f1)<eps ) return x1;
00248 
00249     // now x0<x1, f(x0)<0, f(x1)>0
00250     // Firstly 5 bisections
00251     for( cnt=0; cnt<5; cnt++)
00252     {
00253         x2 = (x0 + x1)/2;                       // next point
00254         f2 = F5(x2);                            // f(x2)
00255         if( fabs(f2)<eps ) return x2;
00256         if( f2>0 ) { x1=x2; f1=f2; }
00257         else       { x0=x2; f0=f2; }
00258     }
00259 
00260     // At each step:
00261     // x0<x1, f(x0)<0, f(x1)>0.
00262     // x2 - next value
00263     // we hope that x0 < x2 < x1, but not necessarily
00264     do {
00265         cnt++;
00266         if( x2<=x0 || x2>= x1 ) x2 = (x0 + x1)/2;       // now  x0 < x2 < x1
00267         f2 = F5(x2);                                                            // f(x2)
00268         if( fabs(f2)<eps ) return x2;
00269         if( f2>0 ) { x1=x2; f1=f2; }
00270         else       { x0=x2; f0=f2; }
00271         f2s= (((5*x2+4*a)*x2+3*b)*x2+2*c)*x2+d;         // f'(x2)
00272         if( fabs(f2s)<eps ) { x2=1e99; continue; }
00273         dx = f2/f2s;
00274         x2 -= dx;
00275     } while(fabs(dx)>eps);
00276     return x2;
00277 } // SolveP5_1(double a,double b,double c,double d,double e)    // return real root of x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
00278 //-----------------------------------------------------------------------------
00279 int   SolveP5(double *x,double a,double b,double c,double d,double e)   // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
00280 {
00281     double r = x[0] = SolveP5_1(a,b,c,d,e);
00282     double a1 = a+r, b1=b+r*a1, c1=c+r*b1, d1=d+r*c1;
00283     return 1+SolveP4(x+1, a1,b1,c1,d1);
00284 } // SolveP5(double *x,double a,double b,double c,double d,double e)    // solve equation x^5 + a*x^4 + b*x^3 + c*x^2 + d*x + e = 0
00285 //-----------------------------------------------------------------------------
00286 // let f(x ) = a*x^2 + b*x + c and
00287 //     f(x0) = f0,
00288 //     f(x1) = f1,
00289 //     f(x2) = f3
00290 // Then r1, r2 - root of f(x)=0.
00291 // Returns 0, if there are no roots, else return 2.
00292 int Solve2( double x0, double x1, double x2, double f0, double f1, double f2, double &r1, double &r2)
00293 {
00294     double w0 = f0*(x1-x2);
00295     double w1 = f1*(x2-x0);
00296     double w2 = f2*(x0-x1);
00297     double a1 =  w0         + w1         + w2;
00298     double b1 = -w0*(x1+x2) - w1*(x2+x0) - w2*(x0+x1);
00299     double c1 =  w0*x1*x2   + w1*x2*x0   + w2*x0*x1;
00300     double Di =  b1*b1 - 4*a1*c1;       // must be>0!
00301     if( Di<0 ) { r1=r2=1e99; return 0; }
00302     Di =  sqrt(Di);
00303     r1 =  (-b1 + Di)/2/a1;
00304     r2 =  (-b1 - Di)/2/a1;
00305     return 2;
00306 }
00307 //-----------------------------------------------------------------------------
00308 //-----------------------------------------------------------------------------
00309 


asr_mild_calibration_tool
Author(s): Aumann Florian, Heller Florian, Meißner Pascal
autogenerated on Thu Jun 6 2019 21:22:44