poly34.cpp
Go to the documentation of this file.
1 // poly.cpp : solution of cubic and quartic equation
2 // (c) Khashin S.I. http://math.ivanovo.ac.ru/dalgebra/Khashin/index.html
3 // khash2 (at) gmail.com
4 //
5 #include <math.h>
6 
7 #include "MathHelpers/Resectionsolver/poly34.h" // solution of cubic and quartic equation
8 #define TwoPi 6.28318530717958648
9 const double eps=1e-14;
10 //---------------------------------------------------------------------------
11 // x - array of size 3
12 // In case 3 real roots: => x[0], x[1], x[2], return 3
13 // 2 real roots: x[0], x[1], return 2
14 // 1 real root : x[0], x[1] � i*x[2], return 1
15 int SolveP3(double *x,double a,double b,double c) { // solve cubic equation x^3 + a*x^2 + b*x + c
16  double a2 = a*a;
17  double q = (a2 - 3*b)/9;
18  double r = (a*(2*a2-9*b) + 27*c)/54;
19  double r2 = r*r;
20  double q3 = q*q*q;
21  double A,B;
22  if(r2<q3) {
23  double t=r/sqrt(q3);
24  if( t<-1) t=-1;
25  if( t> 1) t= 1;
26  t=acos(t);
27  a/=3; q=-2*sqrt(q);
28  x[0]=q*cos(t/3)-a;
29  x[1]=q*cos((t+TwoPi)/3)-a;
30  x[2]=q*cos((t-TwoPi)/3)-a;
31  return(3);
32  } else {
33  A =-pow(fabs(r)+sqrt(r2-q3),1./3);
34  if( r<0 ) A=-A;
35  B = A==0 ? 0 : q/A;
36 
37  a/=3;
38  x[0] =(A+B)-a;
39  x[1] =-0.5*(A+B)-a;
40  x[2] = 0.5*sqrt(3.)*(A-B);
41  if(fabs(x[2])<eps) { x[2]=x[1]; return(2); }
42  return(1);
43  }
44 }// SolveP3(double *x,double a,double b,double c) {
45 //---------------------------------------------------------------------------
46 // a>=0!
47 void CSqrt( double x, double y, double &a, double &b) // returns: a+i*s = sqrt(x+i*y)
48 {
49  double r = sqrt(x*x+y*y);
50  if( y==0 ) {
51  r = sqrt(r);
52  if(x>=0) { a=r; b=0; } else { a=0; b=r; }
53  } else { // y != 0
54  a = sqrt(0.5*(x+r));
55  b = 0.5*y/a;
56  }
57 }
58 //---------------------------------------------------------------------------
59 int SolveP4Bi(double *x, double b, double d) // solve equation x^4 + b*x^2 + d = 0
60 {
61  double D = b*b-4*d;
62  if( D>=0 )
63  {
64  double sD = sqrt(D);
65  double x1 = (-b+sD)/2;
66  double x2 = (-b-sD)/2; // x2 <= x1
67  if( x2>=0 ) // 0 <= x2 <= x1, 4 real roots
68  {
69  double sx1 = sqrt(x1);
70  double sx2 = sqrt(x2);
71  x[0] = -sx1;
72  x[1] = sx1;
73  x[2] = -sx2;
74  x[3] = sx2;
75  return 4;
76  }
77  if( x1 < 0 ) // x2 <= x1 < 0, two pair of imaginary roots
78  {
79  double sx1 = sqrt(-x1);
80  double sx2 = sqrt(-x2);
81  x[0] = 0;
82  x[1] = sx1;
83  x[2] = 0;
84  x[3] = sx2;
85  return 0;
86  }
87  // now x2 < 0 <= x1 , two real roots and one pair of imginary root
88  double sx1 = sqrt( x1);
89  double sx2 = sqrt(-x2);
90  x[0] = -sx1;
91  x[1] = sx1;
92  x[2] = 0;
93  x[3] = sx2;
94  return 2;
95  } else { // if( D < 0 ), two pair of compex roots
96  double sD2 = 0.5*sqrt(-D);
97  CSqrt(-0.5*b, sD2, x[0],x[1]);
98  CSqrt(-0.5*b,-sD2, x[2],x[3]);
99  return 0;
100  } // if( D>=0 )
101 } // SolveP4Bi(double *x, double b, double d) // solve equation x^4 + b*x^2 d
102 //---------------------------------------------------------------------------
103 #define SWAP(a,b) { t=b; b=a; a=t; }
104 static void dblSort3( double &a, double &b, double &c) // make: a <= b <= c
105 {
106  double t;
107  if( a>b ) SWAP(a,b); // now a<=b
108  if( c<b ) {
109  SWAP(b,c); // now a<=b, b<=c
110  if( a>b ) SWAP(a,b);// now a<=b
111  }
112 }
113 //---------------------------------------------------------------------------
114 int SolveP4De(double *x, double b, double c, double d) // solve equation x^4 + b*x^2 + c*x + d
115 {
116  //if( c==0 ) return SolveP4Bi(x,b,d); // After that, c!=0
117  if( fabs(c)<1e-14*(fabs(b)+fabs(d)) ) return SolveP4Bi(x,b,d); // After that, c!=0
118 
119  int res3 = SolveP3( x, 2*b, b*b-4*d, -c*c); // solve resolvent
120  // by Viet theorem: x1*x2*x3=-c*c not equals to 0, so x1!=0, x2!=0, x3!=0
121  if( res3>1 ) // 3 real roots,
122  {
123  dblSort3(x[0], x[1], x[2]); // sort roots to x[0] <= x[1] <= x[2]
124  // Note: x[0]*x[1]*x[2]= c*c > 0
125  if( x[0] > 0) // all roots are positive
126  {
127  double sz1 = sqrt(x[0]);
128  double sz2 = sqrt(x[1]);
129  double sz3 = sqrt(x[2]);
130  // Note: sz1*sz2*sz3= -c (and not equal to 0)
131  if( c>0 )
132  {
133  x[0] = (-sz1 -sz2 -sz3)/2;
134  x[1] = (-sz1 +sz2 +sz3)/2;
135  x[2] = (+sz1 -sz2 +sz3)/2;
136  x[3] = (+sz1 +sz2 -sz3)/2;
137  return 4;
138  }
139  // now: c<0
140  x[0] = (-sz1 -sz2 +sz3)/2;
141  x[1] = (-sz1 +sz2 -sz3)/2;
142  x[2] = (+sz1 -sz2 -sz3)/2;
143  x[3] = (+sz1 +sz2 +sz3)/2;
144  return 4;
145  } // if( x[0] > 0) // all roots are positive
146  // now x[0] <= x[1] < 0, x[2] > 0
147  // two pair of comlex roots
148  double sz1 = sqrt(-x[0]);
149  double sz2 = sqrt(-x[1]);
150  double sz3 = sqrt( x[2]);
151 
152  if( c>0 ) // sign = -1
153  {
154  x[0] = -sz3/2;
155  x[1] = ( sz1 -sz2)/2; // x[0]�i*x[1]
156  x[2] = sz3/2;
157  x[3] = (-sz1 -sz2)/2; // x[2]�i*x[3]
158  return 0;
159  }
160  // now: c<0 , sign = +1
161  x[0] = sz3/2;
162  x[1] = (-sz1 +sz2)/2;
163  x[2] = -sz3/2;
164  x[3] = ( sz1 +sz2)/2;
165  return 0;
166  } // if( res3>1 ) // 3 real roots,
167  // now resoventa have 1 real and pair of compex roots
168  // x[0] - real root, and x[0]>0,
169  // x[1]�i*x[2] - complex roots,
170  double sz1 = sqrt(x[0]);
171  double szr, szi;
172  CSqrt(x[1], x[2], szr, szi); // (szr+i*szi)^2 = x[1]+i*x[2]
173  if( c>0 ) // sign = -1
174  {
175  x[0] = -sz1/2-szr; // 1st real root
176  x[1] = -sz1/2+szr; // 2nd real root
177  x[2] = sz1/2;
178  x[3] = szi;
179  return 2;
180  }
181  // now: c<0 , sign = +1
182  x[0] = sz1/2-szr; // 1st real root
183  x[1] = sz1/2+szr; // 2nd real root
184  x[2] = -sz1/2;
185  x[3] = szi;
186  return 2;
187 } // SolveP4De(double *x, double b, double c, double d) // solve equation x^4 + b*x^2 + c*x + d
188 //-----------------------------------------------------------------------------
189 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
190 {
191  double fxs= ((4*x+3*a)*x+2*b)*x+c; // f'(x)
192  if( fxs==0 ) return 1e99;
193  double fx = (((x+a)*x+b)*x+c)*x+d; // f(x)
194  return x - fx/fxs;
195 }
196 //-----------------------------------------------------------------------------
197 // x - array of size 4
198 // return 4: 4 real roots x[0], x[1], x[2], x[3], possible multiple roots
199 // return 2: 2 real roots x[0], x[1] and complex x[2]�i*x[3],
200 // return 0: two pair of complex roots: x[0]�i*x[1], x[2]�i*x[3],
201 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
202  // move to a=0:
203  double d1 = d + 0.25*a*( 0.25*b*a - 3./64*a*a*a - c);
204  double c1 = c + 0.5*a*(0.25*a*a - b);
205  double b1 = b - 0.375*a*a;
206  int res = SolveP4De( x, b1, c1, d1);
207  if( res==4) { x[0]-= a/4; x[1]-= a/4; x[2]-= a/4; x[3]-= a/4; }
208  else if (res==2) { x[0]-= a/4; x[1]-= a/4; x[2]-= a/4; }
209  else { x[0]-= a/4; x[2]-= a/4; }
210  // one Newton step for each real root:
211  if( res>0 )
212  {
213  x[0] = N4Step(x[0], a,b,c,d);
214  x[1] = N4Step(x[1], a,b,c,d);
215  }
216  if( res>2 )
217  {
218  x[2] = N4Step(x[2], a,b,c,d);
219  x[3] = N4Step(x[3], a,b,c,d);
220  }
221  return res;
222 }
223 //-----------------------------------------------------------------------------
224 #define F5(t) (((((t+a)*t+b)*t+c)*t+d)*t+e)
225 //-----------------------------------------------------------------------------
226 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
227 {
228  int cnt;
229  if( fabs(e)<eps ) return 0;
230 
231  double brd = fabs(a); // brd - border of real roots
232  if( fabs(b)>brd ) brd = fabs(b);
233  if( fabs(c)>brd ) brd = fabs(c);
234  if( fabs(d)>brd ) brd = fabs(d);
235  if( fabs(e)>brd ) brd = fabs(e);
236  brd++; // brd - border of real roots
237 
238  double x0, f0; // less, than root
239  double x1, f1; // greater, than root
240  double x2, f2, f2s; // next values, f(x2), f'(x2)
241  double dx = 0.0;
242 
243  if( e<0 ) { x0 = 0; x1 = brd; f0=e; f1=F5(x1); x2 = 0.01*brd; }
244  else { x0 =-brd; x1 = 0; f0=F5(x0); f1=e; x2 =-0.01*brd; }
245 
246  if( fabs(f0)<eps ) return x0;
247  if( fabs(f1)<eps ) return x1;
248 
249  // now x0<x1, f(x0)<0, f(x1)>0
250  // Firstly 5 bisections
251  for( cnt=0; cnt<5; cnt++)
252  {
253  x2 = (x0 + x1)/2; // next point
254  f2 = F5(x2); // f(x2)
255  if( fabs(f2)<eps ) return x2;
256  if( f2>0 ) { x1=x2; f1=f2; }
257  else { x0=x2; f0=f2; }
258  }
259 
260  // At each step:
261  // x0<x1, f(x0)<0, f(x1)>0.
262  // x2 - next value
263  // we hope that x0 < x2 < x1, but not necessarily
264  do {
265  cnt++;
266  if( x2<=x0 || x2>= x1 ) x2 = (x0 + x1)/2; // now x0 < x2 < x1
267  f2 = F5(x2); // f(x2)
268  if( fabs(f2)<eps ) return x2;
269  if( f2>0 ) { x1=x2; f1=f2; }
270  else { x0=x2; f0=f2; }
271  f2s= (((5*x2+4*a)*x2+3*b)*x2+2*c)*x2+d; // f'(x2)
272  if( fabs(f2s)<eps ) { x2=1e99; continue; }
273  dx = f2/f2s;
274  x2 -= dx;
275  } while(fabs(dx)>eps);
276  return x2;
277 } // 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
278 //-----------------------------------------------------------------------------
279 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
280 {
281  double r = x[0] = SolveP5_1(a,b,c,d,e);
282  double a1 = a+r, b1=b+r*a1, c1=c+r*b1, d1=d+r*c1;
283  return 1+SolveP4(x+1, a1,b1,c1,d1);
284 } // 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
285 //-----------------------------------------------------------------------------
286 // let f(x ) = a*x^2 + b*x + c and
287 // f(x0) = f0,
288 // f(x1) = f1,
289 // f(x2) = f3
290 // Then r1, r2 - root of f(x)=0.
291 // Returns 0, if there are no roots, else return 2.
292 int Solve2( double x0, double x1, double x2, double f0, double f1, double f2, double &r1, double &r2)
293 {
294  double w0 = f0*(x1-x2);
295  double w1 = f1*(x2-x0);
296  double w2 = f2*(x0-x1);
297  double a1 = w0 + w1 + w2;
298  double b1 = -w0*(x1+x2) - w1*(x2+x0) - w2*(x0+x1);
299  double c1 = w0*x1*x2 + w1*x2*x0 + w2*x0*x1;
300  double Di = b1*b1 - 4*a1*c1; // must be>0!
301  if( Di<0 ) { r1=r2=1e99; return 0; }
302  Di = sqrt(Di);
303  r1 = (-b1 + Di)/2/a1;
304  r2 = (-b1 - Di)/2/a1;
305  return 2;
306 }
307 //-----------------------------------------------------------------------------
308 //-----------------------------------------------------------------------------
309 
double SolveP5_1(double a, double b, double c, double d, double e)
Definition: poly34.cpp:226
void CSqrt(double x, double y, double &a, double &b)
Definition: poly34.cpp:47
int SolveP4Bi(double *x, double b, double d)
Definition: poly34.cpp:59
int SolveP4(double *x, double a, double b, double c, double d)
Definition: poly34.cpp:201
#define TwoPi
Definition: poly34.cpp:8
int SolveP3(double *x, double a, double b, double c)
Definition: poly34.cpp:15
int SolveP4De(double *x, double b, double c, double d)
Definition: poly34.cpp:114
const double eps
Definition: poly34.cpp:9
#define F5(t)
Definition: poly34.cpp:224
double N4Step(double x, double a, double b, double c, double d)
Definition: poly34.cpp:189
int Solve2(double x0, double x1, double x2, double f0, double f1, double f2, double &r1, double &r2)
Definition: poly34.cpp:292
int SolveP5(double *x, double a, double b, double c, double d, double e)
Definition: poly34.cpp:279
#define SWAP(a, b)
Definition: poly34.cpp:103
static void dblSort3(double &a, double &b, double &c)
Definition: poly34.cpp:104


asr_mild_calibration_tool
Author(s): Aumann Florian, Heller Florian, Meißner Pascal
autogenerated on Mon Dec 2 2019 03:11:43