00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifdef HAVE_CONFIG_H
00033 #include <config.h>
00034 #endif
00035
00036 #include "irplib_polynomial.h"
00037 #include <assert.h>
00038 #include <math.h>
00039
00040 #include <float.h>
00041
00042
00048
00051
00052
00053
00054
00055 #define IRPLIB_SWAP(a,b) { const double t=(a);(a)=(b);(b)=t; }
00056
00057 #if 0
00058 #define irplib_trace() cpl_msg_info(cpl_func, "%d: Trace", __LINE__)
00059 #else
00060 #define irplib_trace()
00061 #endif
00062
00063
00064
00065
00066
00067 static double irplib_polynomial_eval_2_max(double, double, double, cpl_boolean,
00068 double, double);
00069
00070 static double irplib_polynomial_eval_3_max(double, double, double, double,
00071 cpl_boolean, double, double, double);
00072
00073
00074 static cpl_boolean irplib_polynomial_solve_1d_2(double, double, double,
00075 double *, double *);
00076 static cpl_boolean irplib_polynomial_solve_1d_3(double, double, double, double,
00077 double *, double *, double *,
00078 cpl_boolean *,
00079 cpl_boolean *);
00080
00081 static void irplib_polynomial_solve_1d_31(double, double, double *, double *,
00082 double *, cpl_boolean *);
00083
00084 static void irplib_polynomial_solve_1d_32(double, double, double, double *,
00085 double *, double *, cpl_boolean *);
00086
00087 static void irplib_polynomial_solve_1d_3r(double, double, double, double,
00088 double *, double *, double *);
00089
00090 static void irplib_polynomial_solve_1d_3c(double, double, double,
00091 double, double, double,
00092 double *, double *, double *,
00093 cpl_boolean *, cpl_boolean *);
00094
00095 static cpl_error_code irplib_polynomial_solve_1d_4(double, double, double,
00096 double, double, cpl_size *,
00097 double *, double *,
00098 double *, double *);
00099
00100 static cpl_error_code irplib_polynomial_solve_1d_nonzero(cpl_polynomial *,
00101 cpl_vector *,
00102 cpl_size *);
00103
00104 static cpl_error_code irplib_polynomial_divide_1d_root(cpl_polynomial *, double,
00105 double *);
00106
00107 #ifdef IPRLIB_POLYNOMIAL_USE_MONOMIAL_ROOT
00108 static double irplib_polynomial_depress_1d(cpl_polynomial *);
00109 #endif
00110
00111
00112
00113
00114
00115
00141
00142 cpl_error_code irplib_polynomial_solve_1d_all(const cpl_polynomial * self,
00143 cpl_vector * roots,
00144 cpl_size * preal)
00145 {
00146
00147 cpl_error_code error = CPL_ERROR_NONE;
00148 cpl_polynomial * p;
00149
00150 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00151 cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
00152 cpl_ensure_code(preal != NULL, CPL_ERROR_NULL_INPUT);
00153 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00154 CPL_ERROR_INVALID_TYPE);
00155 cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
00156 CPL_ERROR_DATA_NOT_FOUND);
00157 cpl_ensure_code(cpl_polynomial_get_degree(self) ==
00158 cpl_vector_get_size(roots), CPL_ERROR_INCOMPATIBLE_INPUT);
00159
00160 *preal = 0;
00161
00162 p = cpl_polynomial_duplicate(self);
00163
00164 error = irplib_polynomial_solve_1d_nonzero(p, roots, preal);
00165
00166 cpl_polynomial_delete(p);
00167
00168 return error ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;
00169
00170 }
00171
00174
00187
00188 static cpl_error_code irplib_polynomial_solve_1d_nonzero(cpl_polynomial * self,
00189 cpl_vector * roots,
00190 cpl_size * preal)
00191 {
00192 cpl_error_code error = CPL_ERROR_NONE;
00193 const cpl_size ncoeffs = 1 + cpl_polynomial_get_degree(self);
00194
00195 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00196 cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
00197 cpl_ensure_code(preal != NULL, CPL_ERROR_NULL_INPUT);
00198 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00199 CPL_ERROR_INVALID_TYPE);
00200 cpl_ensure_code(ncoeffs > 1, CPL_ERROR_DATA_NOT_FOUND);
00201 cpl_ensure_code(*preal >= 0, CPL_ERROR_ILLEGAL_INPUT);
00202 cpl_ensure_code(ncoeffs + *preal == 1+cpl_vector_get_size(roots),
00203 CPL_ERROR_INCOMPATIBLE_INPUT);
00204
00205 switch (ncoeffs) {
00206
00207 case 2 : {
00208 const cpl_size i1 = 1;
00209 const cpl_size i0 = 0;
00210 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00211 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00212
00213 assert( p1 != 0.0 );
00214
00215 cpl_vector_set(roots, (*preal)++, -p0/p1);
00216 break;
00217 }
00218 case 3 : {
00219 const cpl_size i2 = 2;
00220 const cpl_size i1 = 1;
00221 const cpl_size i0 = 0;
00222 const double p2 = cpl_polynomial_get_coeff(self, &i2);
00223 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00224 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00225 double x1, x2;
00226
00227 assert( p2 != 0.0 );
00228
00229 if (irplib_polynomial_solve_1d_2(p2, p1, p0, &x1, &x2)) {
00230
00231 cpl_vector_set(roots, (*preal) , x1);
00232 cpl_vector_set(roots, (*preal)+1, x2);
00233 } else {
00234 cpl_vector_set(roots, (*preal)++, x1);
00235 cpl_vector_set(roots, (*preal)++, x2);
00236 }
00237 break;
00238 }
00239 case 4 : {
00240 const cpl_size i3 = 3;
00241 const cpl_size i2 = 2;
00242 const cpl_size i1 = 1;
00243 const cpl_size i0 = 0;
00244 const double p3 = cpl_polynomial_get_coeff(self, &i3);
00245 const double p2 = cpl_polynomial_get_coeff(self, &i2);
00246 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00247 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00248 double x1, x2, x3;
00249
00250 assert( p3 != 0.0 );
00251
00252 if (irplib_polynomial_solve_1d_3(p3, p2, p1, p0, &x1, &x2, &x3,
00253 NULL, NULL)) {
00254 cpl_vector_set(roots, (*preal)++, x1);
00255
00256 cpl_vector_set(roots, (*preal) , x2);
00257 cpl_vector_set(roots, (*preal)+1, x3);
00258 } else {
00259 cpl_vector_set(roots, (*preal)++, x1);
00260 cpl_vector_set(roots, (*preal)++, x2);
00261 cpl_vector_set(roots, (*preal)++, x3);
00262 }
00263 break;
00264 }
00265 case 5 : {
00266 const cpl_size i4 = 4;
00267 const cpl_size i3 = 3;
00268 const cpl_size i2 = 2;
00269 const cpl_size i1 = 1;
00270 const cpl_size i0 = 0;
00271 const double p4 = cpl_polynomial_get_coeff(self, &i4);
00272 const double p3 = cpl_polynomial_get_coeff(self, &i3);
00273 const double p2 = cpl_polynomial_get_coeff(self, &i2);
00274 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00275 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00276 double x1, x2, x3, x4;
00277 cpl_size nreal;
00278
00279 assert( p4 != 0.0 );
00280
00281 error = irplib_polynomial_solve_1d_4(p4, p3, p2, p1, p0, &nreal,
00282 &x1, &x2, &x3, &x4);
00283 if (!error) {
00284 cpl_vector_set(roots, (*preal) , x1);
00285 cpl_vector_set(roots, (*preal)+1, x2);
00286 cpl_vector_set(roots, (*preal)+2, x3);
00287 cpl_vector_set(roots, (*preal)+3, x4);
00288
00289 *preal += nreal;
00290 }
00291 break;
00292 }
00293
00294 default: {
00295
00296
00297 const cpl_size n0 = ncoeffs-1;
00298 #ifndef IPRLIB_POLYNOMIAL_USE_MONOMIAL_ROOT
00299 const double pn0 = cpl_polynomial_get_coeff(self, &n0);
00300 const cpl_size n1 = ncoeffs-2;
00301 const double pn1 = cpl_polynomial_get_coeff(self, &n1);
00302
00303
00304 const double rmean = pn0 != 0.0 ? -pn1 / (pn0 * (double)n0) : 0.0;
00305 double root = rmean;
00306
00307 assert( pn0 != 0.0 );
00308
00309 #else
00310
00311 cpl_polynomial * copy = cpl_polynomial_duplicate(self);
00312 const cpl_size i0 = 0;
00313 const double rmean = irplib_polynomial_depress_1d(copy);
00314 const double c0 = cpl_polynomial_get_coeff(copy, &i0);
00315 double root = rmean + ((n0&1) && c0 < 0.0 ? -1.0 : 1.0)
00316 * pow(fabs(c0), 1.0/n0);
00317
00318 cpl_polynomial_delete(copy);
00319 #endif
00320
00321 error = cpl_polynomial_solve_1d(self, root, &root, 1);
00322
00323 if (!error) {
00324
00325 cpl_vector_set(roots, (*preal)++, root);
00326
00327 irplib_polynomial_divide_1d_root(self, root, NULL);
00328
00329 error = irplib_polynomial_solve_1d_nonzero(self, roots, preal);
00330
00331 if (!error && *preal > 1) {
00332
00333
00334
00335
00336 cpl_vector * reals = cpl_vector_wrap(*preal,
00337 cpl_vector_get_data(roots));
00338 cpl_vector_sort(reals, 1);
00339 (void)cpl_vector_unwrap(reals);
00340 }
00341 }
00342 break;
00343 }
00344 }
00345
00346 return error ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;
00347 }
00348
00349
00361
00362 static cpl_boolean irplib_polynomial_solve_1d_2(double p2, double p1, double p0,
00363 double * px1,
00364 double * px2) {
00365
00366 const double sqrtD = sqrt(p1 * p1 < 4.0 * p2 * p0
00367 ? 4.0 * p2 * p0 - p1 * p1
00368 : p1 * p1 - 4.0 * p2 * p0);
00369 cpl_boolean is_complex = CPL_FALSE;
00370 double x1 = -0.5 * p1 / p2;
00371 double x2;
00372
00373
00374 double res0 = irplib_polynomial_eval_2_max(p2, p1, p0, CPL_FALSE, x1, x1);
00375 double res;
00376
00377 assert(px1 != NULL );
00378 assert(px2 != NULL );
00379
00380 *px2 = *px1 = x1;
00381
00382
00383
00384
00385 if (p1 > 0.0) {
00386 x1 = -0.5 * (p1 + sqrtD);
00387 irplib_trace();
00388 } else {
00389 x1 = -0.5 * (p1 - sqrtD);
00390 irplib_trace();
00391 }
00392
00393
00394 x2 = p0 / x1;
00395 x1 /= p2;
00396
00397 res = irplib_polynomial_eval_2_max(p2, p1, p0, CPL_FALSE, x1, x2);
00398
00399 if (res < res0) {
00400 res0 = res;
00401 if (x2 > x1) {
00402 *px1 = x1;
00403 *px2 = x2;
00404 irplib_trace();
00405 } else {
00406 *px1 = x2;
00407 *px2 = x1;
00408 irplib_trace();
00409 }
00410 }
00411
00412
00413
00414 x1 = -0.5 * p1 / p2;
00415 x2 = 0.5 * sqrtD / fabs(p2);
00416
00417 res = irplib_polynomial_eval_2_max(p2, p1, p0, CPL_TRUE, x1, x2);
00418
00419 if (res < res0) {
00420 *px1 = x1;
00421 *px2 = x2;
00422 is_complex = CPL_TRUE;
00423 irplib_trace();
00424 }
00425
00426 return is_complex;
00427
00428 }
00429
00430
00431
00444
00445 static double irplib_polynomial_eval_2_max(double p2, double p1, double p0,
00446 cpl_boolean is_c,
00447 double x1, double x2)
00448 {
00449 double res;
00450
00451 if (is_c) {
00452 res = fabs(p0 + x1 * (p1 + x1 * p2) - p2 * x2 * x2);
00453 irplib_trace();
00454 } else {
00455 const double r1 = fabs(p0 + x1 * (p1 + x1 * p2));
00456 const double r2 = fabs(p0 + x2 * (p1 + x2 * p2));
00457
00458 res = r1 > r2 ? r1 : r2;
00459 irplib_trace();
00460 }
00461
00462 return res;
00463 }
00464
00465
00466
00481
00482 static double irplib_polynomial_eval_3_max(double p3, double p2,
00483 double p1, double p0,
00484 cpl_boolean is_c,
00485 double x1, double x2, double x3)
00486 {
00487 const double r1 = fabs(p0 + x1 * (p1 + x1 * (p2 + x1 * p3)));
00488 double res;
00489
00490 if (is_c) {
00491 const double r2 = fabs(p0 + x2 * (p1 + x2 * (p2 + x2 * p3))
00492 - x3 * x3 * ( 3.0 * p3 * x2 + p2));
00493
00494 res = r1 > r2 ? r1 : r2;
00495 irplib_trace();
00496 } else {
00497 const double r2 = fabs(p0 + x2 * (p1 + x2 * (p2 + x2 * p3)));
00498 const double r3 = fabs(p0 + x3 * (p1 + x3 * (p2 + x3 * p3)));
00499 res = r1 > r2 ? (r1 > r3 ? r1 : r3) : (r2 > r3 ? r2 : r3);
00500 irplib_trace();
00501 }
00502
00503
00504
00505 return res;
00506 }
00507
00508
00509
00528
00529 static cpl_boolean irplib_polynomial_solve_1d_3(double p3, double p2, double p1,
00530 double p0,
00531 double * px1,
00532 double * px2,
00533 double * px3,
00534 cpl_boolean * pdbl1,
00535 cpl_boolean * pdbl2) {
00536 cpl_boolean is_complex = CPL_FALSE;
00537 const double a = p2/p3;
00538 const double b = p1/p3;
00539 const double c = p0/p3;
00540
00541 const double q = (a * a - 3.0 * b);
00542 const double r = (a * (2.0 * a * a - 9.0 * b) + 27.0 * c);
00543
00544 const double Q = q / 9.0;
00545 const double R = r / 54.0;
00546
00547 const double Q3 = Q * Q * Q;
00548 const double R2 = R * R;
00549
00550 double x1 = DBL_MAX;
00551 double x2 = DBL_MAX;
00552 double x3 = DBL_MAX;
00553 double xx1 = DBL_MAX;
00554 double xx2 = DBL_MAX;
00555 double xx3 = DBL_MAX;
00556
00557 double resx = DBL_MAX;
00558 double res = DBL_MAX;
00559 cpl_boolean is_first = CPL_TRUE;
00560
00561 cpl_boolean dbl2;
00562
00563
00564 assert(px1 != NULL );
00565
00566 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00567 if (pdbl2 != NULL) *pdbl2 = CPL_FALSE;
00568
00569 dbl2 = CPL_FALSE;
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579 if ((R2 >= Q3 && R != 0.0) || R2 > Q3) {
00580
00581 cpl_boolean is_c = CPL_FALSE;
00582
00583 irplib_polynomial_solve_1d_3c(a, c, Q, Q3, R, R2, &x1, &x2, &x3,
00584 &is_c, &dbl2);
00585
00586
00587 res = resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, is_c,
00588 x1, x2, x3);
00589
00590 is_first = CPL_FALSE;
00591
00592 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00593 if (!is_c && pdbl2 != NULL) *pdbl2 = dbl2;
00594 is_complex = is_c;
00595 irplib_trace();
00596
00597 }
00598
00599 if (Q > 0.0 && fabs(R / (Q * sqrt(Q))) <= 1.0) {
00600
00601
00602
00603
00604
00605
00606 irplib_polynomial_solve_1d_3r(a, c, Q, R, &xx1, &xx2, &xx3);
00607
00608 resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, CPL_FALSE,
00609 xx1, xx2, xx3);
00610
00611 if (is_first || (dbl2 ? resx < res : resx <= res)) {
00612 is_first = CPL_FALSE;
00613 res = resx;
00614 x1 = xx1;
00615 x2 = xx2;
00616 x3 = xx3;
00617 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00618 if (pdbl2 != NULL) *pdbl2 = CPL_FALSE;
00619 is_complex = CPL_FALSE;
00620 irplib_trace();
00621 }
00622 }
00623
00624 if (Q >= 0) {
00625 cpl_boolean dbl1 = CPL_FALSE;
00626
00627
00628 irplib_polynomial_solve_1d_32(a, c, Q, &xx1, &xx2, &xx3, &dbl2);
00629
00630 resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, CPL_FALSE,
00631 xx1, xx2, xx3);
00632
00633
00634
00635
00636
00637 if (is_first || resx <= res) {
00638 is_first = CPL_FALSE;
00639 res = resx;
00640 x1 = xx1;
00641 x2 = xx2;
00642 x3 = xx3;
00643 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00644 if (pdbl2 != NULL) *pdbl2 = dbl2;
00645 is_complex = CPL_FALSE;
00646 irplib_trace();
00647 }
00648
00649
00650
00651
00652
00653 irplib_polynomial_solve_1d_31(a, Q, &xx1, &xx2, &xx3, &dbl1);
00654
00655 resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, CPL_FALSE,
00656 xx1, xx2, xx3);
00657
00658 if (resx <= res) {
00659 is_first = CPL_FALSE;
00660
00661 x1 = xx1;
00662 x2 = xx2;
00663 x3 = xx3;
00664 if (pdbl1 != NULL) *pdbl1 = dbl1;
00665 if (pdbl2 != NULL) *pdbl2 = CPL_FALSE;
00666 is_complex = CPL_FALSE;
00667 irplib_trace();
00668 }
00669
00670 }
00671
00672 if (px2 != NULL && px3 != NULL) {
00673 *px1 = x1;
00674 *px2 = x2;
00675 *px3 = x3;
00676 irplib_trace();
00677 } else if (is_complex) {
00678 *px1 = x1;
00679 irplib_trace();
00680 } else {
00681 *px1 = x3;
00682 irplib_trace();
00683 }
00684
00685 return is_complex;
00686 }
00687
00688
00702
00703 static void irplib_polynomial_solve_1d_31(double a, double Q,
00704 double * px1, double * px2,
00705 double * px3, cpl_boolean * pdbl1)
00706 {
00707
00708 const double sqrtQ = sqrt (Q);
00709
00710 double x1, x2, x3;
00711
00712 x2 = x1 = -sqrtQ - a / 3.0;
00713 x3 = 2.0 * sqrtQ - a / 3.0;
00714 if (pdbl1 != NULL) *pdbl1 = CPL_TRUE;
00715
00716 *px1 = x1;
00717 *px2 = x2;
00718 *px3 = x3;
00719
00720 irplib_trace();
00721 return;
00722 }
00723
00724
00739
00740 static void irplib_polynomial_solve_1d_32(double a, double c, double Q,
00741 double * px1, double * px2,
00742 double * px3, cpl_boolean * pdbl2)
00743 {
00744
00745 const double sqrtQ = sqrt (Q);
00746
00747 double x1 = DBL_MAX;
00748 double x2 = DBL_MAX;
00749 double x3 = DBL_MAX;
00750
00751 if (a > 0.0) {
00752
00753 x1 = -2.0 * sqrtQ - a / 3.0;
00754
00755
00756 x3 = x2 = -a < x1 ? -sqrt(fabs(c / x1)) : sqrt(fabs(c / x1));
00757 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00758 irplib_trace();
00759 } else if (a < 0.0) {
00760
00761 x3 = x2 = sqrtQ - a / 3.0;
00762 x1 = -c / (x2 * x2);
00763 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00764 irplib_trace();
00765 } else {
00766 x1 = -2.0 * sqrtQ;
00767 x3 = x2 = sqrtQ;
00768 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00769 irplib_trace();
00770 }
00771
00772 *px1 = x1;
00773 *px2 = x2;
00774 *px3 = x3;
00775
00776 return;
00777 }
00778
00779
00799
00800 static void irplib_polynomial_solve_1d_3c(double a, double c,
00801 double Q, double Q3,
00802 double R, double R2,
00803 double * px1,
00804 double * px2, double * px3,
00805 cpl_boolean * pis_c,
00806 cpl_boolean * pdbl2)
00807 {
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817 const double sgnR = (R >= 0 ? 1.0 : -1.0);
00818 const double A = -sgnR * pow (fabs (R) + sqrt (R2 - Q3), 1.0 / 3.0);
00819 const double B = Q / A;
00820
00821 double x1 = DBL_MAX;
00822 double x2 = DBL_MAX;
00823 double x3 = DBL_MAX;
00824 cpl_boolean is_complex = CPL_FALSE;
00825
00826 if (( A > -B && a > 0.0) || (A < -B && a < 0.0)) {
00827
00828
00829
00830 x2 = -0.5 * (A + B) - a / 3.0;
00831
00832 x3 = 0.5 * CPL_MATH_SQRT3 * fabs(A - B);
00833
00834 x1 = -c / (x2 * x2 + x3 * x3);
00835 irplib_trace();
00836 } else {
00837
00838 x1 = A + B - a / 3.0;
00839
00840 x3 = 0.5 * CPL_MATH_SQRT3 * fabs(A - B);
00841
00842 if (x3 > 0.0) {
00843
00844 x2 = -0.5 * (A + B) - a / 3.0;
00845 irplib_trace();
00846 } else {
00847
00848 x2 = -a < x1 ? -sqrt(fabs(c / x1)) : sqrt(fabs(c / x1));
00849 x3 = 0.0;
00850 irplib_trace();
00851 }
00852 }
00853
00854 if (x3 > 0.0) {
00855 is_complex = CPL_TRUE;
00856 irplib_trace();
00857 } else {
00858
00859
00860 x3 = x2;
00861 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00862 irplib_trace();
00863 }
00864
00865 *px1 = x1;
00866 *px2 = x2;
00867 *px3 = x3;
00868 *pis_c = is_complex;
00869
00870 return;
00871 }
00872
00873
00888
00889 static void irplib_polynomial_solve_1d_3r(double a, double c,
00890 double Q, double R,
00891 double * px1,
00892 double * px2, double * px3)
00893 {
00894
00895 const double sqrtQ = sqrt(Q);
00896 const double theta = acos (R / (Q * sqrtQ));
00897
00898
00899
00900
00901
00902 #define TR1 (-2.0 * sqrtQ * cos( theta / 3.0))
00903 #define TR2 (-2.0 * sqrtQ * cos((theta - CPL_MATH_2PI) / 3.0))
00904 #define TR3 (-2.0 * sqrtQ * cos((theta + CPL_MATH_2PI) / 3.0))
00905
00906
00907
00908
00909
00910
00911
00912
00913 double x1 = DBL_MAX;
00914 double x2 = DBL_MAX;
00915 double x3 = DBL_MAX;
00916
00917 if (a > 0.0) {
00918 x1 = TR1 - a / 3.0;
00919 if (TR2 > 0.0 && (TR2 + TR3) > 2.0 * a) {
00920
00921 x3 = TR3 - a / 3.0;
00922 x2 = -c / ( x1 * x3 );
00923 irplib_trace();
00924 } else {
00925
00926
00927
00928 x2 = TR2 - a / 3.0;
00929
00930 x3 = -c / ( x1 * x2 );
00931 irplib_trace();
00932 }
00933 } else if (a < 0.0) {
00934 x3 = TR3 - a / 3.0;
00935 if (TR2 < 0.0 && (TR1 + TR2) > 2.0 * a) {
00936 x1 = TR1 - a / 3.0;
00937 x2 = -c / ( x1 * x3 );
00938 irplib_trace();
00939 } else {
00940 x2 = TR2 - a / 3.0;
00941 x1 = -c / ( x2 * x3 );
00942 irplib_trace();
00943 }
00944 } else {
00945 x1 = TR1;
00946 x2 = TR2;
00947 x3 = TR3;
00948 irplib_trace();
00949 }
00950
00951 assert(x1 < x3);
00952
00953 if (x1 > x2) {
00954
00955
00956
00957
00958
00959
00960
00961 x1 = x2 = 0.5 * ( x1 + x2 );
00962 irplib_trace();
00963 } else if (x2 > x3) {
00964
00965
00966
00967
00968
00969
00970
00971 x3 = x2 = 0.5 * ( x2 + x3 );
00972 irplib_trace();
00973 }
00974
00975 *px1 = x1;
00976 *px2 = x2;
00977 *px3 = x3;
00978
00979 return;
00980 }
00981
00982
01000
01001 static cpl_error_code irplib_polynomial_solve_1d_4(double p4, double p3,
01002 double p2, double p1,
01003 double p0, cpl_size * preal,
01004 double * px1, double * px2,
01005 double * px3, double * px4)
01006 {
01007
01008
01009 const double a = (p2 - 0.375 * p3 * p3 / p4) / p4;
01010 const double b = (p1 - 0.5 * (p2 - 0.25 * p3 * p3 / p4 ) * p3 / p4 ) / p4;
01011 const double c =
01012 (p0 - 0.25 * (p1 - 0.25 * (p2 - 0.1875 * p3 * p3 / p4 ) * p3 / p4
01013 ) * p3 / p4 ) / p4;
01014
01015 double x1 = DBL_MAX;
01016 double x2 = DBL_MAX;
01017 double x3 = DBL_MAX;
01018 double x4 = DBL_MAX;
01019
01020 assert(preal != NULL );
01021 assert(px1 != NULL );
01022 assert(px2 != NULL );
01023 assert(px3 != NULL );
01024 assert(px4 != NULL );
01025
01026 *preal = 4;
01027
01028 if (c == 0.0) {
01029
01030
01031
01032 cpl_boolean dbl1, dbl2;
01033 const cpl_boolean is_real =
01034 !irplib_polynomial_solve_1d_3(1.0, 0.0, a, b, &x1, &x3, &x4,
01035 &dbl1, &dbl2);
01036
01037 x1 -= 0.25 * p3 / p4;
01038 x2 = -0.25 * p3 / p4;
01039 x3 -= 0.25 * p3 / p4;
01040 if (is_real) {
01041
01042 if (dbl2) {
01043 x4 = x3;
01044 assert( x1 <= x2);
01045 assert( x2 <= x3);
01046 } else {
01047 x4 -= 0.25 * p3 / p4;
01048
01049 if (x2 > x3) {
01050 IRPLIB_SWAP(x2, x3);
01051 }
01052 if (dbl1) {
01053 assert( x1 <= x2);
01054 assert( x2 <= x3);
01055 assert( x2 <= x4);
01056 } else {
01057 assert( x1 < x2);
01058 assert( x2 < x4);
01059 }
01060 }
01061 } else {
01062 *preal = 2;
01063
01064 if (x1 > x2) {
01065 assert( x3 <= x2 );
01066
01067 IRPLIB_SWAP(x1, x2);
01068 } else {
01069 assert( x3 >= x2 );
01070 }
01071 }
01072
01073 } else if (b == 0.0) {
01074
01075 double u1, u2;
01076 const cpl_boolean is_complex = irplib_polynomial_solve_1d_2(1.0, a, c,
01077 &u1, &u2);
01078
01079 if (is_complex) {
01080
01081 const double norm = sqrt(u1*u1 + u2*u2);
01082 const double v1 = sqrt(0.5*(norm+u1));
01083 const double v2 = u2 / sqrt(2.0*(norm+u1));
01084
01085
01086 x1 = -0.25 * p3 / p4 - v1;
01087 x3 = -0.25 * p3 / p4 + v1;
01088
01089 x4 = x2 = v2;
01090
01091 *preal = 0;
01092
01093 } else if (u1 >= 0.0) {
01094
01095 const double sv1 = sqrt(u1);
01096 const double sv2 = sqrt(u2);
01097
01098
01099 *preal = 4;
01100
01101 x1 = -0.25 * p3 / p4 - sv2;
01102 x2 = -0.25 * p3 / p4 - sv1;
01103 x3 = -0.25 * p3 / p4 + sv1;
01104 x4 = -0.25 * p3 / p4 + sv2;
01105 } else if (u2 < 0.0) {
01106
01107 const double sv1 = sqrt(-u2);
01108 const double sv2 = sqrt(-u1);
01109
01110
01111 *preal = 0;
01112
01113 x1 = x3 = -0.25 * p3 / p4;
01114
01115 x2 = sv1;
01116 x4 = sv2;
01117 } else {
01118
01119 const double sv1 = sqrt(-u1);
01120 const double sv2 = sqrt(u2);
01121
01122
01123 *preal = 2;
01124
01125 x1 = -0.25 * p3 / p4 - sv2;
01126 x2 = -0.25 * p3 / p4 + sv2;
01127
01128 x3 = -0.25 * p3 / p4;
01129 x4 = sv1;
01130 }
01131 } else {
01132
01133 const double q2 = -a;
01134 const double q1 = -4.0 * c;
01135 const double q0 = 4.0 * a * c - b * b;
01136 double u1, sqrtd, sqrtrd;
01137 double z1, z2, z3, z4;
01138
01139 cpl_boolean is_complex1, is_complex2;
01140
01141
01142
01143 (void)irplib_polynomial_solve_1d_3(1.0, q2, q1, q0, &u1, NULL, NULL,
01144 NULL, NULL);
01145
01146
01147 assert( u1 > a );
01148
01149 sqrtd = sqrt(u1 - a);
01150
01151 sqrtrd = 0.5 * b/sqrtd;
01152
01153 is_complex1 = irplib_polynomial_solve_1d_2(1.0, sqrtd, 0.5*u1 - sqrtrd,
01154 &z1, &z2);
01155
01156 is_complex2 = irplib_polynomial_solve_1d_2(1.0, -sqrtd, 0.5*u1 + sqrtrd,
01157 &z3, &z4);
01158
01159 z1 -= 0.25 * p3 / p4;
01160 z3 -= 0.25 * p3 / p4;
01161 if (!is_complex1) z2 -= 0.25 * p3 / p4;
01162 if (!is_complex2) z4 -= 0.25 * p3 / p4;
01163
01164 if (!is_complex1 && is_complex2) {
01165 *preal = 2;
01166 x1 = z1;
01167 x2 = z2;
01168 x3 = z3;
01169 x4 = z4;
01170 } else if (is_complex1 && !is_complex2) {
01171 *preal = 2;
01172 x1 = z3;
01173 x2 = z4;
01174 x3 = z1;
01175 x4 = z2;
01176 } else if (is_complex1 && is_complex2) {
01177 *preal = 0;
01178
01179 if (z1 < z3 || (z1 == z3 && z2 <= z4)) {
01180 x1 = z1;
01181 x2 = z2;
01182 x3 = z3;
01183 x4 = z4;
01184 } else {
01185 x1 = z3;
01186 x2 = z4;
01187 x3 = z1;
01188 x4 = z2;
01189 }
01190 } else {
01191 *preal = 4;
01192
01193 if (z3 >= z2) {
01194 x1 = z1;
01195 x2 = z2;
01196 x3 = z3;
01197 x4 = z4;
01198 } else if (z4 <= z1) {
01199 x1 = z3;
01200 x2 = z4;
01201 x3 = z1;
01202 x4 = z2;
01203 } else if (z2 > z4) {
01204 x1 = z3;
01205 x2 = z1;
01206 x3 = z4;
01207 x4 = z2;
01208 } else {
01209 x1 = z1;
01210 x2 = z3;
01211 x3 = z2;
01212 x4 = z4;
01213 }
01214 }
01215 }
01216
01217 *px1 = x1;
01218 *px2 = x2;
01219 *px3 = x3;
01220 *px4 = x4;
01221
01222 return CPL_ERROR_NONE;
01223 }
01224
01225 #ifdef IPRLIB_POLYNOMIAL_USE_MONOMIAL_ROOT
01226
01234
01235 static double irplib_polynomial_depress_1d(cpl_polynomial * self)
01236 {
01237
01238 const cpl_size degree = cpl_polynomial_get_degree(self);
01239 const cpl_size nc1 = degree - 1;
01240 const double an = cpl_polynomial_get_coeff(self, °ree);
01241 const double an1 = cpl_polynomial_get_coeff(self, &nc1);
01242 const double rmean = an != 0.0 ? -an1/(an * (double)degree) : 0.0;
01243 cpl_size i;
01244
01245
01246 cpl_ensure(degree > 0, CPL_ERROR_DATA_NOT_FOUND, 0.0);
01247
01248 assert( an != 0.0 );
01249
01250 if (rmean != 0.0) {
01251
01252 cpl_polynomial_shift_1d(self, 0, rmean);
01253
01254 }
01255
01256
01257 for (i = 0; i < nc1; i++) {
01258 const double ai = cpl_polynomial_get_coeff(self, &i) / an;
01259 cpl_polynomial_set_coeff(self, &i, ai);
01260 }
01261
01262 cpl_polynomial_set_coeff(self, &nc1, 0.0);
01263 cpl_polynomial_set_coeff(self, °ree, 1.0);
01264
01265 return rmean;
01266 }
01267 #endif
01268
01269
01284
01285 static
01286 cpl_error_code irplib_polynomial_divide_1d_root(cpl_polynomial * p, double r,
01287 double * pres)
01288 {
01289
01290 const cpl_size n = cpl_polynomial_get_degree(p);
01291 double sum;
01292 cpl_size i;
01293
01294
01295 cpl_ensure_code(p != NULL, CPL_ERROR_NULL_INPUT);
01296 cpl_ensure_code(cpl_polynomial_get_dimension(p) == 1,
01297 CPL_ERROR_INVALID_TYPE);
01298 cpl_ensure_code(n > 0, CPL_ERROR_DATA_NOT_FOUND);
01299
01300 sum = cpl_polynomial_get_coeff(p, &n);
01301 cpl_polynomial_set_coeff(p, &n, 0.0);
01302
01303 for (i = n-1; i >= 0; i--) {
01304 const double coeff = cpl_polynomial_get_coeff(p, &i);
01305
01306 cpl_polynomial_set_coeff(p, &i, sum);
01307
01308 sum = coeff + r * sum;
01309
01310 }
01311
01312 if (pres != NULL) *pres = sum;
01313
01314 return CPL_ERROR_NONE;
01315 }