00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00031 #include <math.h>
00032 #include <iostream>
00033
00034 namespace Archon
00035 {
00036 namespace Math
00037 {
00038 static const double nought = 0;
00039 static const double doub1 = 1;
00040 static const double doub2 = 2;
00041 static const double doub3 = 3;
00042 static const double doub4 = 4;
00043 static const double doub6 = 6;
00044 static const double doub12 = 12;
00045 static const double doub24 = 24;
00046 static const double inv2 = 1.0 / 2;
00047 static const double inv3 = 1.0 / 3;
00048 static const double inv4 = 1.0 / 4;
00049 static const double rt3 = sqrt(3);
00050
00051 static bool initialized = false;
00052
00053 static double doubmin;
00054 static double doubmax;
00055 static double doubtol;
00056
00057 static void initialize()
00058 {
00059 doubtol = doub1;
00060 while(doub1+doubtol > doub1) doubtol *= inv2;
00061 doubtol = sqrt(doubtol);
00062
00063 doubmin = inv2;
00064 for(int i=1; i<=100; ++i)
00065 {
00066 doubmin = doubmin*doubmin ;
00067 if((doubmin*doubmin) <= (doubmin*doubmin*inv2)) break;
00068 }
00069 doubmax = 0.7/sqrt(doubmin);
00070
00071 initialized = true;
00072
00073 std::cerr << "Quartic solver initialized\n";
00074 }
00075
00083 static int qudrtc(double b, double c, double rts[4], double dis)
00084 {
00085 int nquad;
00086 double rtdis;
00087
00088 if(dis >= nought)
00089 {
00090 nquad = 2;
00091 rtdis = sqrt(dis);
00092 if(b > nought) rts[0] = ( -b - rtdis)*inv2;
00093 else rts[0] = ( -b + rtdis)*inv2;
00094 if(rts[0] == nought) rts[1] = -b;
00095 else rts[1] = c/rts[0];
00096 }
00097 else
00098 {
00099 nquad = 0;
00100 rts[0] = nought;
00101 rts[1] = nought;
00102 }
00103 return nquad;
00104 }
00105
00113 static inline double acos3(double x)
00114 {
00115 return cos(acos(x)*inv3);
00116 }
00117
00125 static double curoot(double x)
00126 {
00127 double value;
00128 double absx;
00129 int neg;
00130
00131 neg = 0;
00132 absx = x;
00133 if(x < nought)
00134 {
00135 absx = -x;
00136 neg = 1;
00137 }
00138 value = exp(log(absx)*inv3);
00139 if(neg == 1) value = -value;
00140 return value;
00141 }
00142
00166 static double cubic(double p, double q, double r)
00167 {
00168 double po3, po3sq, qo3;
00169 double uo3, u2o3, uo3sq4, uo3cu4;
00170 double v, vsq, wsq;
00171 double m, mcube = 0, n;
00172 double muo3, s, scube, t, cosk, sinsqk;
00173 double root;
00174
00175 m = nought;
00176 if((p > doubmax) || (p < -doubmax)) root = -p;
00177 else if((q > doubmax) || (q < -doubmax))
00178 {
00179 if(q > nought) root = -r/q;
00180 else root = -sqrt(-q);
00181 }
00182 else if((r > doubmax)|| (r < -doubmax)) root = -curoot(r);
00183 else
00184 {
00185 po3 = p*inv3;
00186 po3sq = po3*po3;
00187 if(po3sq > doubmax) root = -p ;
00188 else
00189 {
00190 v = r + po3*(po3sq + po3sq - q);
00191 if((v > doubmax) || (v < -doubmax)) root = -p;
00192 else
00193 {
00194 vsq = v*v;
00195 qo3 = q*inv3;
00196 uo3 = qo3 - po3sq;
00197 u2o3 = uo3 + uo3;
00198 if((u2o3 > doubmax) || (u2o3 < -doubmax))
00199 {
00200 if(p == nought)
00201 {
00202 if(q > nought) root = -r/q;
00203 else root = -sqrt(-q);
00204 }
00205 else root = -q/p;
00206 }
00207 uo3sq4 = u2o3*u2o3;
00208 if(uo3sq4 > doubmax)
00209 {
00210 if(p == nought)
00211 {
00212 if(q > nought) root = -r/q;
00213 else root = -sqrt(fabs(q));
00214 }
00215 else root = -q/p;
00216 }
00217 uo3cu4 = uo3sq4*uo3;
00218 wsq = uo3cu4 + vsq;
00219 if(wsq >= nought)
00220 {
00221
00222
00223
00224 if(v <= nought) mcube = ( -v + sqrt(wsq))*inv2;
00225 if(v > nought) mcube = ( -v - sqrt(wsq))*inv2;
00226 m = curoot(mcube);
00227 if(m != nought) n = -uo3/m;
00228 else n = nought;
00229 root = m + n - po3;
00230 }
00231 else
00232 {
00233
00234
00235
00236 if(uo3 < nought)
00237 {
00238 muo3 = -uo3;
00239 s = sqrt(muo3);
00240 scube = s*muo3;
00241 t = -v/(scube+scube);
00242 cosk = acos3(t);
00243 if(po3 < nought)
00244 root = (s+s)*cosk - po3;
00245 else
00246 {
00247 sinsqk = doub1 - cosk*cosk;
00248 if(sinsqk < nought) sinsqk = nought;
00249 root = s*( -cosk - rt3*sqrt(sinsqk)) - po3;
00250 }
00251 }
00252 else
00253
00254
00255
00256 root = curoot(v) - po3 ;
00257 }
00258 }
00259 }
00260 }
00261 return root;
00262 }
00263
00282 static int ferrari(double a, double b, double c, double d, double rts[4])
00283 {
00284 int nquar, n1, n2;
00285 double asq, ainv2;
00286 double v1[4], v2[4];
00287 double p, q, r;
00288 double y;
00289 double e, f, esq, fsq, ef;
00290 double g, gg, h, hh;
00291
00292
00293 asq = a*a;
00294
00295 p = b ;
00296 q = a*c-doub4*d ;
00297 r = (asq - doub4*b)*d + c*c ;
00298 y = cubic(p,q,r) ;
00299
00300 esq = inv4*asq - b - y;
00301 if(esq < nought) return 0;
00302
00303 fsq = inv4*y*y - d;
00304 if(fsq < nought) return 0;
00305
00306 ef = -(inv4*a*y + inv2*c);
00307 if(a > nought && y > nought && c > nought ||
00308 a > nought && y < nought && c < nought ||
00309 a < nought && y > nought && c < nought ||
00310 a < nought && y < nought && c > nought ||
00311 a == nought || y == nought || c == nought)
00312
00313 {
00314 if(b < nought && y < nought && esq > nought)
00315 {
00316 e = sqrt(esq);
00317 f = ef/e;
00318 }
00319 else if(d < nought && fsq > nought)
00320 {
00321 f = sqrt(fsq);
00322 e = ef/f;
00323 }
00324 else
00325 {
00326 e = sqrt(esq);
00327 f = sqrt(fsq);
00328 if(ef < nought) f = -f;
00329 }
00330 }
00331 else
00332 {
00333 e = sqrt(esq);
00334 f = sqrt(fsq);
00335 if(ef < nought) f = -f;
00336 }
00337
00338 ainv2 = a*inv2;
00339 g = ainv2 - e;
00340 gg = ainv2 + e;
00341 if(b > nought && y > nought ||
00342 b < nought && y < nought)
00343 {
00344 if(a > nought && e != nought) g = (b + y)/gg;
00345 else if(e != nought) gg = (b + y)/g;
00346 }
00347 if(y == nought && f == nought)
00348 {
00349 h = nought;
00350 hh = nought;
00351 }
00352 else if(f > nought && y < nought ||
00353 f < nought && y > nought)
00354 {
00355 hh = -inv2*y + f;
00356 h = d/hh;
00357 }
00358 else
00359 {
00360 h = -inv2*y - f;
00361 hh = d/h;
00362 }
00363 n1 = qudrtc(gg,hh,v1, gg*gg - doub4*hh);
00364 n2 = qudrtc(g,h,v2, g*g - doub4*h);
00365 nquar = n1+n2;
00366 rts[0] = v1[0];
00367 rts[1] = v1[1];
00368 rts[n1+0] = v2[0];
00369 rts[n1+1] = v2[1];
00370 return nquar;
00371 }
00372
00393 static int neumark(double a, double b, double c, double d, double rts[4])
00394 {
00395 int nquar, n1, n2;
00396 double y, g, gg, h, hh, gdis, gdisrt, hdis, hdisrt, g1, g2, h1, h2;
00397 double bmy, gerr, herr, y4, d4, bmysq;
00398 double v1[4], v2[4];
00399 double asq;
00400 double p, q, r;
00401 double hmax, gmax;
00402
00403
00404 asq = a*a;
00405
00406 p = -b*doub2;
00407 q = b*b + a*c - doub4*d;
00408 r = (c - a*b)*c + asq*d;
00409 y = cubic(p,q,r);
00410
00411 bmy = b - y;
00412 y4 = y*doub4;
00413 d4 = d*doub4;
00414 bmysq = bmy*bmy;
00415 gdis = asq - y4;
00416 hdis = bmysq - d4;
00417 if(gdis < nought || hdis < nought) return 0;
00418
00419 g1 = a*inv2;
00420 h1 = bmy*inv2;
00421 gerr = asq + y4;
00422 herr = hdis;
00423 if(d > nought) herr = bmysq + d4;
00424 if(y < nought || herr*gdis > gerr*hdis)
00425 {
00426 gdisrt = sqrt(gdis);
00427 g2 = gdisrt*inv2;
00428 if(gdisrt != nought) h2 = (a*h1 - c)/gdisrt;
00429 else h2 = nought;
00430 }
00431 else
00432 {
00433 hdisrt = sqrt(hdis);
00434 h2 = hdisrt*inv2;
00435 if(hdisrt != nought) g2 = (a*h1 - c)/hdisrt;
00436 else g2 = nought;
00437 }
00438
00439
00440
00441
00442 h = h1 - h2;
00443 hh = h1 + h2;
00444 hmax = hh;
00445 if(hmax < nought) hmax = -hmax;
00446 if(hmax < h) hmax = h;
00447 if(hmax < -h) hmax = -h;
00448 if(h1 > nought && h2 > nought) h = d/hh;
00449 if(h1 < nought && h2 < nought) h = d/hh;
00450 if(h1 > nought && h2 < nought) hh = d/h;
00451 if(h1 < nought && h2 > nought) hh = d/h;
00452 if(h > hmax) h = hmax;
00453 if(h < -hmax) h = -hmax;
00454 if(hh > hmax) hh = hmax;
00455 if(hh < -hmax) hh = -hmax;
00456
00457 g = g1 - g2;
00458 gg = g1 + g2;
00459 gmax = gg;
00460 if(gmax < nought) gmax = -gmax;
00461 if(gmax < g) gmax = g;
00462 if(gmax < -g) gmax = -g;
00463 if(g1 > nought && g2 > nought) g = y/gg;
00464 if(g1 < nought && g2 < nought) g = y/gg;
00465 if(g1 > nought && g2 < nought) gg = y/g;
00466 if(g1 < nought && g2 > nought) gg = y/g;
00467 if(g > gmax) g = gmax;
00468 if(g < -gmax) g = -gmax;
00469 if(gg > gmax) gg = gmax;
00470 if(gg < -gmax) gg = -gmax;
00471
00472 n1 = qudrtc(gg,hh,v1, gg*gg - doub4*hh);
00473 n2 = qudrtc(g,h,v2, g*g - doub4*h);
00474 nquar = n1+n2;
00475 rts[0] = v1[0];
00476 rts[1] = v1[1];
00477 rts[n1+0] = v2[0];
00478 rts[n1+1] = v2[1];
00479
00480 return nquar;
00481 }
00482
00488 static void errors(double a, double b, double c, double d,
00489 double rts[4], double rterr[4], int nrts)
00490 {
00491 double deriv,test;
00492
00493 if(nrts > 0)
00494 {
00495 for(int k = 0; k < nrts; ++k)
00496 {
00497 test = (((rts[k]+a)*rts[k]+b)*rts[k]+c)*rts[k]+d;
00498 if(test == nought) rterr[k] = nought;
00499 else
00500 {
00501 deriv =
00502 ((doub4*rts[k]+doub3*a)*rts[k]+doub2*b)*rts[k]+c;
00503 if(deriv != nought)
00504 rterr[k] = fabs(test/deriv);
00505 else
00506 {
00507 deriv = (doub12*rts[k]+doub6*a)*rts[k]+doub2*b;
00508 if(deriv != nought)
00509 rterr[k] = sqrt(fabs(test/deriv));
00510 else
00511 {
00512 deriv = doub24*rts[k]+doub6*a;
00513 if(deriv != nought)
00514 rterr[k] = curoot(fabs(test/deriv));
00515 else
00516 rterr[k] = sqrt(sqrt(fabs(test)/doub24));
00517 }
00518 }
00519 }
00520
00521 }
00522 }
00523
00524 }
00525
00537 int quarticSolve(double a, double b, double c, double d,
00538 double rts[4], double rterr[4])
00539 {
00540 if(!initialized) initialize();
00541
00542 int j, k, nq, nr = 0;
00543 double odd, even;
00544 double roots[4];
00545
00546 if(a < 0) odd = -a; else odd = a;
00547 if(c < 0) odd -= c; else odd += c;
00548 if(b < 0) even = -b; else even = b;
00549 if(d < 0) even -= d; else even += d;
00550 if(odd < even*doubtol)
00551 {
00552 nq = qudrtc(b,d,roots,b*b-doub4*d);
00553 j = 0;
00554 for(k = 0; k < nq; ++k)
00555 {
00556 if(roots[k] > 0)
00557 {
00558 rts[j] = sqrt(roots[k]);
00559 rts[j+1] = -rts[j];
00560 ++j; ++j;
00561 }
00562 }
00563 nr = j;
00564 }
00565 else
00566 {
00567 if(a < 0) k = 1; else k = 0;
00568 if(b < 0) k += k+1; else k +=k;
00569 if(c < 0) k += k+1; else k +=k;
00570 if(d < 0) k += k+1; else k +=k;
00571 switch(k)
00572 {
00573 case 0: nr = ferrari(a,b,c,d,rts); break;
00574 case 1: nr = neumark(a,b,c,d,rts); break;
00575 case 2: nr = neumark(a,b,c,d,rts); break;
00576 case 3: nr = ferrari(a,b,c,d,rts); break;
00577 case 4: nr = ferrari(a,b,c,d,rts); break;
00578 case 5: nr = neumark(a,b,c,d,rts); break;
00579 case 6: nr = ferrari(a,b,c,d,rts); break;
00580 case 7: nr = ferrari(a,b,c,d,rts); break;
00581 case 8: nr = neumark(a,b,c,d,rts); break;
00582 case 9: nr = ferrari(a,b,c,d,rts); break;
00583 case 10: nr = ferrari(a,b,c,d,rts); break;
00584 case 11: nr = neumark(a,b,c,d,rts); break;
00585 case 12: nr = ferrari(a,b,c,d,rts); break;
00586 case 13: nr = ferrari(a,b,c,d,rts); break;
00587 case 14: nr = ferrari(a,b,c,d,rts); break;
00588 case 15: nr = ferrari(a,b,c,d,rts); break;
00589 }
00590 }
00591 if(rterr) errors(a, b, c, d, rts, rterr, nr);
00592 return nr;
00593 }
00594
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723 }
00724 }