00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "rootsolve.h"
00019
00020
00021
00022
00023 namespace NUM
00024 {
00025
00026
00027
00028 const PolyRootSolver_Direct::Params PolyRootSolver_Direct::defaults =
00029 {
00030 INIT_FIELD(nearly_zero) 1e-10
00031 };
00032
00033
00034
00035
00036
00037 int PolyRootSolver_Direct::Solve_1(const dbl *c,dbl *r)
00038 {
00039
00040
00041 if(c[1]==0.0) return(0);
00042
00043 r[0]=-c[0]/c[1];
00044
00045 return(1);
00046 }
00047
00048
00049
00050
00051
00052 int PolyRootSolver_Direct::Solve_2(const dbl *c,dbl *r)
00053 {
00054 if(c[2]==0.0)
00055 {
00056
00057 return(Solve_1(c,r));
00058 }
00059
00060 #if 0
00061
00062
00063
00064 dbl p = -0.5*c[1] / c[2];
00065 dbl q = c[0] / c[2];
00066 dbl D = sqr(p) - q;
00067
00068 if(fabs(D)<par.nearly_zero)
00069 { r[0]=p; return(1); }
00070
00071 if(D>0.0)
00072 {
00073 D = sqrt(D);
00074 r[0]=p+D;
00075 r[1]=p-D;
00076 return(2);
00077 }
00078 #else
00079
00080
00081
00082
00083
00084
00085 dbl D = sqr(c[1]) - 4.0*c[0]*c[2];
00086
00087 if(fabs(D)<par.nearly_zero)
00088 { r[0] = -0.5*c[1]/c[2]; return(1); }
00089
00090 if(D>0.0)
00091 {
00092 D = sqrt(D);
00093 #if 0
00094
00095 dbl f = -0.5/c[2];
00096 r[0] = (c[1]+D)*f;
00097 r[1] = (c[1]-D)*f;
00098 #else
00099
00100
00101
00102
00103 D = -0.5*( c[1]<0 ? (c[1]-D) : (c[1]+D) );
00104
00105
00106
00107 r[0] = c[0]/D;
00108 r[1] = D/c[2];
00109 #endif
00110 return(2);
00111 }
00112 #endif
00113
00114 return(0);
00115 }
00116
00117
00118
00119
00120
00121
00122 int PolyRootSolver_Direct::Solve_3(const dbl *c,dbl *r)
00123 {
00124 if(c[3]==0.0)
00125 {
00126
00127 return(Solve_2(c,r));
00128 }
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 dbl cc = 1/c[3];
00139 dbl A = c[2]*cc;
00140 dbl B = c[1]*cc;
00141 dbl C = c[0]*cc;
00142
00143 dbl sq_A = sqr(A);
00144
00145
00146 dbl p = (sq_A-3.0*B) / 9.0;
00147 dbl q = A * (sq_A-4.5*B) / 27 + 0.5*C;
00148 dbl cb_p = p*p*p;
00149 dbl D = sqr(q)-cb_p;
00150
00151 dbl sub = A/-3.0;
00152
00153
00154
00155
00156 #if 1
00157 if(fabs(D)<par.nearly_zero)
00158 {
00159 CritAssert(!"CHECK ME!\n");
00160
00161 if(fabs(q)<par.nearly_zero)
00162 {
00163
00164 r[0]=sub;
00165 return(1);
00166 }
00167
00168 dbl u = cbrt(-q);
00169 r[0]=2.0*u+sub;
00170 r[1]=sub-u;
00171 return(2);
00172 }
00173 #endif
00174
00175 if(D>0.0)
00176 {
00177
00178
00179
00180
00181 #if 0
00182
00183 D = sqrt(D);
00184 r[0] = cbrt(D-q) - cbrt(D+q) + sub;
00185 #elif 0
00186
00187
00188 D = -cbrt( sqrt(q*q-cb_p) + q );
00189 r[0] = (D + p/D) + sub;
00190 #else
00191
00192
00193
00194
00195 D = sqrt(q*q-cb_p);
00196 D = q<0 ? cbrt(D-q) : -cbrt(D+q) ;
00197 r[0] = (D + p/D) + sub;
00198 #endif
00199 return(1);
00200 }
00201
00202
00203 dbl phi = (1.0/3) * acos(q / sqrt(cb_p));
00204 dbl t = -2*sqrt(p);
00205 r[0] = t * cos(phi ) + sub;
00206 r[1] = t * cos(phi+FPConst<dbl>::mul_pi_2_3) + sub;
00207 r[2] = t * cos(phi-FPConst<dbl>::mul_pi_2_3) + sub;
00208 return(3);
00209 }
00210
00211
00212
00213
00214
00215
00216 int PolyRootSolver_Direct::Solve_4(const dbl *c,dbl *_r)
00217 {
00218 if(c[4]==0.0)
00219 {
00220
00221 return(Solve_3(c,_r));
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 dbl f=1.0/c[4];
00233 dbl A = c[3]*f;
00234 dbl B = c[2]*f;
00235 dbl C = c[1]*f;
00236 dbl D = c[0]*f;
00237
00238
00239
00240
00241
00242 dbl sq_A = A * A;
00243 dbl p = -0.375 * sq_A + B;
00244 dbl q = (0.125 * sq_A - 0.5*B)*A + C;
00245
00246 dbl r = -0.01171875*sq_A*sq_A + 0.0625*sq_A*B - 0.25*A*C + D;
00247
00248 dbl coeffs[4];
00249 int num;
00250 if(fabs(r)<par.nearly_zero)
00251 {
00252
00253 coeffs[0] = q;
00254 coeffs[1] = p;
00255 coeffs[2] = 0;
00256 coeffs[3] = 1;
00257 num = Solve_3(coeffs,_r);
00258
00259
00260 dbl sub = -0.25*A;
00261 for(int i=0; i<num; i++) _r[i]+=sub;
00262
00263
00264 _r[num++] = sub;
00265 }
00266 else
00267 {
00268
00269 #if 0
00270 coeffs[0] = 0.5*r*p - 0.125*q*q;
00271 coeffs[1] = -r;
00272 coeffs[2] = -0.5*p;
00273 coeffs[3] = 1;
00274 num = Solve_3(coeffs,_r);
00275 if(!num) return(0);
00276
00277
00278 dbl z = _r[0];
00279 #else
00280
00281
00282 dbl z;
00283 do {
00284 dbl sq_p = sqr(p);
00285 dbl pp = (sq_p+12*r)/36.0;
00286 dbl qq = -0.0625*q*q - p*(sq_p-36*r)/216.0;
00287 dbl cb_pp = pp*pp*pp;
00288 dbl D = sqr(qq)-cb_pp;
00289 dbl sub = p/6.0;
00290
00291 if(fabs(D)<par.nearly_zero)
00292 {
00293 if(fabs(qq)<par.nearly_zero)
00294 { z=sub; break; }
00295
00296
00297 z=sub-cbrt(-qq);
00298 break;
00299 }
00300 if(D>0.0)
00301 {
00302 D = sqrt(qq*qq-cb_pp);
00303 D = qq<0 ? cbrt(D-qq) : -cbrt(D+qq) ;
00304 z = (D + pp/D) + sub;
00305 break;
00306 }
00307
00308 z = -2*sqrt(pp) * cos((1.0/3) * acos(qq/sqrt(cb_pp)) ) + sub;
00309
00310
00311 break;
00312 } while(0);
00313 #endif
00314
00315
00316 dbl u = z*z - r;
00317 if(fabs(u)<par.nearly_zero) u=0;
00318 else if(u>0) u=sqrt(u);
00319 else return 0;
00320
00321 dbl v = 2*z - p;
00322 if(fabs(v)<par.nearly_zero) v=0;
00323 else if(v>0) v=sqrt(v);
00324 else return 0;
00325
00326 #if 0
00327 coeffs[0] = z-u;
00328 coeffs[1] = q<0 ? -v : v;
00329 coeffs[2] = 1;
00330 num=Solve_2(coeffs,_r);
00331
00332 coeffs[0] = z+u;
00333 coeffs[1] = -coeffs[1];
00334
00335 num += Solve_2(coeffs,_r+num);
00336
00337
00338 dbl sub = -0.25*A;
00339 for(int i=0; i<num; i++) _r[i]+=sub;
00340 #else
00341
00342
00343 num=0;
00344 dbl c_1 = 0.5 * (q<0 ? -v : v);
00345 bool c_1_gn = c_1>0;
00346 dbl DD = sqr(c_1) - z;
00347 dbl sub = -0.25*A;
00348 dbl D = DD + u;
00349 if(fabs(D)<par.nearly_zero)
00350 { _r[num++] = sub - c_1; }
00351 else if(D>0)
00352 {
00353 D = sqrt(D);
00354 #if 0
00355 dbl sub2 = sub - c_1;
00356 _r[num++] = sub2 - D;
00357 _r[num++] = sub2 + D;
00358 #else
00359 D = c_1_gn ? (c_1+D) : (c_1-D);
00360 _r[num++] = sub - D;
00361 _r[num++] = (u-z)/D + sub;
00362 #endif
00363 }
00364
00365 D = DD - u;
00366 if(fabs(D)<par.nearly_zero)
00367 { _r[num++] = sub + c_1; }
00368 else if(D>0)
00369 {
00370 D = sqrt(D);
00371 #if 0
00372 dbl sub2 = sub + c_1;
00373 _r[num++] = sub2 - D;
00374 _r[num++] = sub2 + D;
00375 #else
00376 D = c_1_gn ? (c_1+D) : (c_1-D);
00377 _r[num++] = D + sub;
00378 _r[num++] = (z+u)/D + sub;
00379 #endif
00380 }
00381 #endif
00382 }
00383
00384 return(num);
00385 }
00386
00387
00388 int PolyRootSolver_Direct::solve(int order,const dbl *c,dbl *r)
00389 {
00390 switch(order)
00391 {
00392 case 1: return(Solve_1(c,r));
00393 case 2: return(Solve_2(c,r));
00394 case 3: return(Solve_3(c,r));
00395 case 4: return(Solve_4(c,r));
00396
00397 }
00398
00399 return(-2);
00400 }
00401
00402
00403 PolyRootSolver_Direct::PolyRootSolver_Direct() :
00404 PolyRootSolver(),
00405 par(defaults)
00406 {
00407
00408 }
00409
00410 PolyRootSolver_Direct::~PolyRootSolver_Direct()
00411 {
00412
00413 }
00414
00415 }
00416
00417
00418 #if 0
00419
00420
00421 int main()
00422 {
00423
00424
00425 dbl c[5],r[4],rB[4];
00426 int deg=2;
00427 #if 1
00428 fprintf(stderr,"DEG=%d\n",deg);
00429 for(int i=0; i<1000000; i++)
00430 {
00431 for(int j=0; j<=deg; j++)
00432 c[j]=(rand()%2000-1000)/100.0;
00433 int n=NUM::SolvePolyRoots_2(c,r);
00434 for(int j=0; j<n; j++)
00435 {
00436 dbl R=NUM::PolvEval(r[j],c,deg);
00437 if(fabs(R)>5e-13)
00438 fprintf(stderr,"[%3d] %g %g %g -> %g for %g (n=%d, j=%d)\n",i,
00439 c[0],c[1],c[2],R,r[j],n,j);
00440 }
00441 }
00442
00443 deg=3;
00444 fprintf(stderr,"DEG=%d\n",deg);
00445 for(int i=0; i<1000000; i++)
00446 {
00447 for(int j=0; j<=deg; j++)
00448 c[j]=(rand()%2000-1000)/100.0;
00449 int n=NUM::SolvePolyRoots_3(c,r);
00450
00451 for(int j=0; j<n; j++)
00452 {
00453 dbl R=NUM::PolvEval(r[j],c,deg);
00454 if(fabs(R)>1e-9)
00455 fprintf(stderr,"[%6d ] %g %g %g %g -> %g for %g (n=%d,j=%d)\n",
00456 i,c[0],c[1],c[2],c[3],R,r[j],n,j);
00457 }
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 }
00474 #endif
00475
00476 deg=4;
00477 fprintf(stderr,"DEG=%d\n",deg);
00478 for(int i=0; i<1000000; i++)
00479 {
00480 for(int j=0; j<=deg; j++)
00481 c[j]=(rand()%2000-1000)/100.0;
00482 int n=NUM::SolvePolyRoots_4(c,r);
00483
00484 for(int j=0; j<n; j++)
00485 {
00486 dbl R=NUM::PolvEval(r[j],c,deg);
00487 if(fabs(R)>1e-5)
00488 fprintf(stderr,"[%6d ] %g %g %g %g %g -> %g for %g (n=%d,j=%d)\n",
00489 i,c[0],c[1],c[2],c[3],c[4],R,r[j],n,j);
00490 }
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 }
00508
00509 return(0);
00510 }
00511 #endif