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 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031
00032
00033
00034
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, int *,
00097 double *, double *,
00098 double *, double *);
00099
00100 static cpl_error_code irplib_polynomial_solve_1d_nonzero(cpl_polynomial *,
00101 cpl_vector *,
00102 int *);
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
00116
00132
00133 cpl_error_code irplib_polynomial_shift_1d(cpl_polynomial * p, int i, double u)
00134 {
00135
00136 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE > CPL_VERSION(4, 5, 0)
00137 cpl_ensure_code(!cpl_polynomial_shift_1d(p, i, u), cpl_error_get_code());
00138 #else
00139 const int ndim = cpl_polynomial_get_dimension(p);
00140
00141 cpl_ensure_code(p != NULL, CPL_ERROR_NULL_INPUT);
00142 cpl_ensure_code(i >= 0, CPL_ERROR_ILLEGAL_INPUT);
00143 cpl_ensure_code(i < ndim, CPL_ERROR_ACCESS_OUT_OF_RANGE);
00144
00145 if (ndim == 1) {
00146
00147 cpl_ensure_code(!cpl_polynomial_shift_1d(p, u), cpl_error_get_code());
00148 } else if (ndim == 2) {
00149 const int ndeg = cpl_polynomial_get_degree(p);
00150 cpl_polynomial * p1d = cpl_polynomial_new(1);
00151 int powers[2];
00152 int * pi2 = powers + 1 - i;
00153
00154 cpl_ensure_code(p1d != NULL, CPL_ERROR_NULL_INPUT);
00155
00156
00157 for (*pi2 = ndeg; *pi2 >=0; (*pi2)--) {
00158 int * pshift = powers + i;
00159
00160
00161
00162
00163 for (*pshift = ndeg - *pi2; *pshift >= 0; (*pshift)--) {
00164
00165 cpl_polynomial_set_coeff(p1d, pshift,
00166 cpl_polynomial_get_coeff(p, powers));
00167 }
00168
00169 cpl_polynomial_shift_1d(p1d, u);
00170
00171
00172 for (*pshift = ndeg - *pi2; *pshift >= 0; (*pshift)--) {
00173
00174 cpl_polynomial_set_coeff(p, powers,
00175 cpl_polynomial_get_coeff(p1d, pshift));
00176 }
00177 }
00178
00179 cpl_polynomial_delete(p1d);
00180 } else {
00181 cpl_ensure_code(0, CPL_ERROR_UNSUPPORTED_MODE);
00182 }
00183
00184 #endif
00185 return CPL_ERROR_NONE;
00186 }
00187
00188
00203
00204 cpl_error_code irplib_polynomial_add(cpl_polynomial * self,
00205 const cpl_polynomial * first,
00206 const cpl_polynomial * second)
00207 {
00208 int degree0 = cpl_polynomial_get_degree(self);
00209 const int degree1 = cpl_polynomial_get_degree(first);
00210 const int degree2 = cpl_polynomial_get_degree(second);
00211 const int maxdeg = degree1 > degree2 ? degree1 : degree2;
00212
00213
00214 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00215 cpl_ensure_code(first != NULL, CPL_ERROR_NULL_INPUT);
00216 cpl_ensure_code(second != NULL, CPL_ERROR_NULL_INPUT);
00217
00218 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00219 cpl_polynomial_get_dimension(first),
00220 CPL_ERROR_INCOMPATIBLE_INPUT);
00221 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00222 cpl_polynomial_get_dimension(second),
00223 CPL_ERROR_INCOMPATIBLE_INPUT);
00224
00225
00226 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00227 CPL_ERROR_UNSUPPORTED_MODE);
00228
00229 if (degree0 < maxdeg) {
00230 degree0 = maxdeg;
00231 } else {
00232
00233 for (; degree0 > maxdeg; degree0--) {
00234 cpl_polynomial_set_coeff(self, °ree0, 0.0);
00235 }
00236 }
00237
00238
00239
00240 for (; degree0 >= 0; degree0--) {
00241 const double val1 = cpl_polynomial_get_coeff(first, °ree0);
00242 const double val2 = cpl_polynomial_get_coeff(second, °ree0);
00243 cpl_polynomial_set_coeff(self, °ree0, val1 + val2);
00244 }
00245
00246 return CPL_ERROR_NONE;
00247 }
00248
00249
00264
00265 cpl_error_code irplib_polynomial_subtract(cpl_polynomial * self,
00266 const cpl_polynomial * first,
00267 const cpl_polynomial * second)
00268 {
00269 int degree0 = cpl_polynomial_get_degree(self);
00270 const int degree1 = cpl_polynomial_get_degree(first);
00271 const int degree2 = cpl_polynomial_get_degree(second);
00272 const int maxdeg = degree1 > degree2 ? degree1 : degree2;
00273
00274
00275 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00276 cpl_ensure_code(first != NULL, CPL_ERROR_NULL_INPUT);
00277 cpl_ensure_code(second != NULL, CPL_ERROR_NULL_INPUT);
00278
00279 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00280 cpl_polynomial_get_dimension(first),
00281 CPL_ERROR_INCOMPATIBLE_INPUT);
00282 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00283 cpl_polynomial_get_dimension(second),
00284 CPL_ERROR_INCOMPATIBLE_INPUT);
00285
00286
00287 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00288 CPL_ERROR_UNSUPPORTED_MODE);
00289
00290 if (degree0 < maxdeg) {
00291 degree0 = maxdeg;
00292 } else {
00293
00294 for (; degree0 > maxdeg; degree0--) {
00295 cpl_polynomial_set_coeff(self, °ree0, 0.0);
00296 }
00297 }
00298
00299
00300
00301 for (; degree0 >= 0; degree0--) {
00302 const double val1 = cpl_polynomial_get_coeff(first, °ree0);
00303 const double val2 = cpl_polynomial_get_coeff(second, °ree0);
00304 cpl_polynomial_set_coeff(self, °ree0, val1 - val2);
00305 }
00306
00307 return CPL_ERROR_NONE;
00308 }
00309
00310
00321
00322 cpl_error_code irplib_polynomial_multiply_scalar(cpl_polynomial * self,
00323 double factor)
00324 {
00325
00326 int degree0;
00327
00328 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00329
00330 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00331 CPL_ERROR_UNSUPPORTED_MODE);
00332
00333 degree0 = cpl_polynomial_get_degree(self);
00334
00335 for (; degree0 >=0; degree0--) {
00336 const double val = cpl_polynomial_get_coeff(self, °ree0);
00337 cpl_polynomial_set_coeff(self, °ree0, factor * val);
00338 }
00339
00340 return CPL_ERROR_NONE;
00341 }
00342
00343
00369
00370 cpl_error_code irplib_polynomial_solve_1d_all(const cpl_polynomial * self,
00371 cpl_vector * roots, int * preal)
00372 {
00373
00374 cpl_error_code error = CPL_ERROR_NONE;
00375 cpl_polynomial * p;
00376
00377 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00378 cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
00379 cpl_ensure_code(preal != NULL, CPL_ERROR_NULL_INPUT);
00380 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00381 CPL_ERROR_INVALID_TYPE);
00382 cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
00383 CPL_ERROR_DATA_NOT_FOUND);
00384 cpl_ensure_code(cpl_polynomial_get_degree(self) ==
00385 cpl_vector_get_size(roots), CPL_ERROR_INCOMPATIBLE_INPUT);
00386
00387 *preal = 0;
00388
00389 p = cpl_polynomial_duplicate(self);
00390
00391 error = irplib_polynomial_solve_1d_nonzero(p, roots, preal);
00392
00393 cpl_polynomial_delete(p);
00394
00395 return error;
00396
00397 }
00398
00401
00427
00428 static cpl_error_code irplib_polynomial_solve_1d_nonzero(cpl_polynomial * self,
00429 cpl_vector * roots,
00430 int * preal)
00431 {
00432 cpl_error_code error = CPL_ERROR_NONE;
00433 const int ncoeffs = 1 + cpl_polynomial_get_degree(self);
00434
00435 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00436 cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
00437 cpl_ensure_code(preal != NULL, CPL_ERROR_NULL_INPUT);
00438 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00439 CPL_ERROR_INVALID_TYPE);
00440 cpl_ensure_code(ncoeffs > 1, CPL_ERROR_DATA_NOT_FOUND);
00441 cpl_ensure_code(*preal >= 0, CPL_ERROR_ILLEGAL_INPUT);
00442 cpl_ensure_code(ncoeffs + *preal == 1+cpl_vector_get_size(roots),
00443 CPL_ERROR_INCOMPATIBLE_INPUT);
00444
00445 switch (ncoeffs) {
00446
00447 case 2 : {
00448 const int i1 = 1;
00449 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00450 const int i0 = 0;
00451 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00452
00453 cpl_vector_set(roots, (*preal)++, -p0/p1);
00454 break;
00455 }
00456 case 3 : {
00457 const int i2 = 2;
00458 const int i1 = 1;
00459 const int i0 = 0;
00460 const double p2 = cpl_polynomial_get_coeff(self, &i2);
00461 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00462 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00463 double x1, x2;
00464
00465 if (irplib_polynomial_solve_1d_2(p2, p1, p0, &x1, &x2)) {
00466
00467 cpl_vector_set(roots, (*preal) , x1);
00468 cpl_vector_set(roots, (*preal)+1, x2);
00469 } else {
00470 cpl_vector_set(roots, (*preal)++, x1);
00471 cpl_vector_set(roots, (*preal)++, x2);
00472 }
00473 break;
00474 }
00475 case 4 : {
00476 const int i3 = 3;
00477 const int i2 = 2;
00478 const int i1 = 1;
00479 const int i0 = 0;
00480 const double p3 = cpl_polynomial_get_coeff(self, &i3);
00481 const double p2 = cpl_polynomial_get_coeff(self, &i2);
00482 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00483 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00484 double x1, x2, x3;
00485
00486 if (irplib_polynomial_solve_1d_3(p3, p2, p1, p0, &x1, &x2, &x3,
00487 NULL, NULL)) {
00488 cpl_vector_set(roots, (*preal)++, x1);
00489
00490 cpl_vector_set(roots, (*preal) , x2);
00491 cpl_vector_set(roots, (*preal)+1, x3);
00492 } else {
00493 cpl_vector_set(roots, (*preal)++, x1);
00494 cpl_vector_set(roots, (*preal)++, x2);
00495 cpl_vector_set(roots, (*preal)++, x3);
00496 }
00497 break;
00498 }
00499 case 5 : {
00500 const int i4 = 4;
00501 const int i3 = 3;
00502 const int i2 = 2;
00503 const int i1 = 1;
00504 const int i0 = 0;
00505 const double p4 = cpl_polynomial_get_coeff(self, &i4);
00506 const double p3 = cpl_polynomial_get_coeff(self, &i3);
00507 const double p2 = cpl_polynomial_get_coeff(self, &i2);
00508 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00509 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00510 double x1, x2, x3, x4;
00511 int nreal;
00512
00513 error = irplib_polynomial_solve_1d_4(p4, p3, p2, p1, p0, &nreal,
00514 &x1, &x2, &x3, &x4);
00515 if (!error) {
00516 cpl_vector_set(roots, (*preal) , x1);
00517 cpl_vector_set(roots, (*preal)+1, x2);
00518 cpl_vector_set(roots, (*preal)+2, x3);
00519 cpl_vector_set(roots, (*preal)+3, x4);
00520
00521 *preal += nreal;
00522 }
00523 break;
00524 }
00525
00526 default: {
00527
00528
00529 #ifndef IPRLIB_POLYNOMIAL_USE_MONOMIAL_ROOT
00530 const int n0 = ncoeffs-1;
00531 const double pn0 = cpl_polynomial_get_coeff(self, &n0);
00532 const int n1 = ncoeffs-2;
00533 const double pn1 = cpl_polynomial_get_coeff(self, &n1);
00534
00535
00536 const double rmean = -pn1 / (pn0 * n0);
00537 double root = rmean;
00538 #else
00539
00540 cpl_polynomial * copy = cpl_polynomial_duplicate(self);
00541 const int i0 = 0;
00542 const double rmean = irplib_polynomial_depress_1d(copy);
00543 const double c0 = cpl_polynomial_get_coeff(copy, &i0);
00544 double root = rmean + ((n0&1) && c0 < 0.0 ? -1.0 : 1.0)
00545 * pow(fabs(c0), 1.0/n0);
00546
00547 cpl_polynomial_delete(copy);
00548 #endif
00549
00550 error = cpl_polynomial_solve_1d(self, root, &root, 1);
00551
00552 if (!error) {
00553
00554 cpl_vector_set(roots, (*preal)++, root);
00555
00556 irplib_polynomial_divide_1d_root(self, root, NULL);
00557
00558 error = irplib_polynomial_solve_1d_nonzero(self, roots, preal);
00559
00560 if (!error && *preal > 1) {
00561
00562
00563
00564
00565 cpl_vector * reals = cpl_vector_wrap(*preal,
00566 cpl_vector_get_data(roots));
00567 cpl_vector_sort(reals, 1);
00568 (void)cpl_vector_unwrap(reals);
00569 }
00570 }
00571 break;
00572 }
00573 }
00574
00575 return error;
00576 }
00577
00578
00590
00591 static cpl_boolean irplib_polynomial_solve_1d_2(double p2, double p1, double p0,
00592 double * px1,
00593 double * px2) {
00594
00595 const double sqrtD = sqrt(fabs(p1 * p1 - 4.0 * p2 * p0));
00596 cpl_boolean is_complex = CPL_FALSE;
00597 double x1 = -0.5 * p1 / p2;
00598 double x2;
00599
00600
00601 double res0 = irplib_polynomial_eval_2_max(p2, p1, p0, CPL_FALSE, x1, x1);
00602 double res;
00603
00604 assert(px1 != NULL );
00605 assert(px2 != NULL );
00606
00607 *px2 = *px1 = x1;
00608
00609
00610
00611
00612 if (p1 > 0.0) {
00613 x1 = -0.5 * (p1 + sqrtD);
00614 irplib_trace();
00615 } else {
00616 x1 = -0.5 * (p1 - sqrtD);
00617 irplib_trace();
00618 }
00619
00620
00621 x2 = p0 / x1;
00622 x1 /= p2;
00623
00624 res = irplib_polynomial_eval_2_max(p2, p1, p0, CPL_FALSE, x1, x2);
00625
00626 if (res < res0) {
00627 res0 = res;
00628 if (x2 > x1) {
00629 *px1 = x1;
00630 *px2 = x2;
00631 irplib_trace();
00632 } else {
00633 *px1 = x2;
00634 *px2 = x1;
00635 irplib_trace();
00636 }
00637 }
00638
00639
00640
00641 x1 = -0.5 * p1 / p2;
00642 x2 = 0.5 * sqrtD / fabs(p2);
00643
00644 res = irplib_polynomial_eval_2_max(p2, p1, p0, CPL_TRUE, x1, x2);
00645
00646 if (res < res0) {
00647 *px1 = x1;
00648 *px2 = x2;
00649 is_complex = CPL_TRUE;
00650 irplib_trace();
00651 }
00652
00653 return is_complex;
00654
00655 }
00656
00657
00658
00671
00672 static double irplib_polynomial_eval_2_max(double p2, double p1, double p0,
00673 cpl_boolean is_c,
00674 double x1, double x2)
00675 {
00676 double res;
00677
00678 if (is_c) {
00679 res = fabs(p0 + x1 * (p1 + x1 * p2) - p2 * x2 * x2);
00680 irplib_trace();
00681 } else {
00682 const double r1 = fabs(p0 + x1 * (p1 + x1 * p2));
00683 const double r2 = fabs(p0 + x2 * (p1 + x2 * p2));
00684
00685 res = r1 > r2 ? r1 : r2;
00686 irplib_trace();
00687 }
00688
00689 return res;
00690 }
00691
00692
00693
00708
00709 static double irplib_polynomial_eval_3_max(double p3, double p2,
00710 double p1, double p0,
00711 cpl_boolean is_c,
00712 double x1, double x2, double x3)
00713 {
00714 const double r1 = fabs(p0 + x1 * (p1 + x1 * (p2 + x1 * p3)));
00715 double res;
00716
00717 if (is_c) {
00718 const double r2 = fabs(p0 + x2 * (p1 + x2 * (p2 + x2 * p3))
00719 - x3 * x3 * ( 3.0 * p3 * x2 + p2));
00720
00721 res = r1 > r2 ? r1 : r2;
00722 irplib_trace();
00723 } else {
00724 const double r2 = fabs(p0 + x2 * (p1 + x2 * (p2 + x2 * p3)));
00725 const double r3 = fabs(p0 + x3 * (p1 + x3 * (p2 + x3 * p3)));
00726 res = r1 > r2 ? (r1 > r3 ? r1 : r3) : (r2 > r3 ? r2 : r3);
00727 irplib_trace();
00728 }
00729
00730
00731
00732 return res;
00733 }
00734
00735
00736
00755
00756 static cpl_boolean irplib_polynomial_solve_1d_3(double p3, double p2, double p1,
00757 double p0,
00758 double * px1,
00759 double * px2,
00760 double * px3,
00761 cpl_boolean * pdbl1,
00762 cpl_boolean * pdbl2) {
00763 cpl_boolean is_complex = CPL_FALSE;
00764 const double a = p2/p3;
00765 const double b = p1/p3;
00766 const double c = p0/p3;
00767
00768 const double q = (a * a - 3.0 * b);
00769 const double r = (a * (2.0 * a * a - 9.0 * b) + 27.0 * c);
00770
00771 const double Q = q / 9.0;
00772 const double R = r / 54.0;
00773
00774 const double Q3 = Q * Q * Q;
00775 const double R2 = R * R;
00776
00777 double x1 = DBL_MAX;
00778 double x2 = DBL_MAX;
00779 double x3 = DBL_MAX;
00780 double xx1 = DBL_MAX;
00781 double xx2 = DBL_MAX;
00782 double xx3 = DBL_MAX;
00783
00784 double resx = DBL_MAX;
00785 double res = DBL_MAX;
00786 cpl_boolean is_first = CPL_TRUE;
00787
00788 cpl_boolean dbl2;
00789
00790
00791 assert(px1 != NULL );
00792
00793 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00794 if (pdbl2 != NULL) *pdbl2 = CPL_FALSE;
00795
00796 dbl2 = CPL_FALSE;
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 if ((R2 >= Q3 && R != 0.0) || R2 > Q3) {
00807
00808 cpl_boolean is_c = CPL_FALSE;
00809
00810 irplib_polynomial_solve_1d_3c(a, c, Q, Q3, R, R2, &x1, &x2, &x3,
00811 &is_c, &dbl2);
00812
00813
00814 res = resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, is_c,
00815 x1, x2, x3);
00816
00817 is_first = CPL_FALSE;
00818
00819 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00820 if (!is_c && pdbl2 != NULL) *pdbl2 = dbl2;
00821 is_complex = is_c;
00822 irplib_trace();
00823
00824 }
00825
00826 if (Q > 0.0 && fabs(R / (Q * sqrt(Q))) <= 1.0) {
00827
00828
00829
00830
00831
00832
00833 irplib_polynomial_solve_1d_3r(a, c, Q, R, &xx1, &xx2, &xx3);
00834
00835 resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, CPL_FALSE,
00836 xx1, xx2, xx3);
00837
00838 if (is_first || (dbl2 ? resx < res : resx <= res)) {
00839 is_first = CPL_FALSE;
00840 res = resx;
00841 x1 = xx1;
00842 x2 = xx2;
00843 x3 = xx3;
00844 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00845 if (pdbl2 != NULL) *pdbl2 = CPL_FALSE;
00846 is_complex = CPL_FALSE;
00847 irplib_trace();
00848 }
00849 }
00850
00851 if (Q >= 0) {
00852 cpl_boolean dbl1 = CPL_FALSE;
00853
00854
00855 irplib_polynomial_solve_1d_32(a, c, Q, &xx1, &xx2, &xx3, &dbl2);
00856
00857 resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, CPL_FALSE,
00858 xx1, xx2, xx3);
00859
00860
00861
00862
00863
00864 if (is_first || resx <= res) {
00865 is_first = CPL_FALSE;
00866 res = resx;
00867 x1 = xx1;
00868 x2 = xx2;
00869 x3 = xx3;
00870 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00871 if (pdbl2 != NULL) *pdbl2 = dbl2;
00872 is_complex = CPL_FALSE;
00873 irplib_trace();
00874 }
00875
00876
00877
00878
00879
00880 irplib_polynomial_solve_1d_31(a, Q, &xx1, &xx2, &xx3, &dbl1);
00881
00882 resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, CPL_FALSE,
00883 xx1, xx2, xx3);
00884
00885 if (resx <= res) {
00886 is_first = CPL_FALSE;
00887 res = resx;
00888 x1 = xx1;
00889 x2 = xx2;
00890 x3 = xx3;
00891 if (pdbl1 != NULL) *pdbl1 = dbl1;
00892 if (pdbl2 != NULL) *pdbl2 = CPL_FALSE;
00893 is_complex = CPL_FALSE;
00894 irplib_trace();
00895 }
00896
00897 }
00898
00899 if (px2 != NULL && px3 != NULL) {
00900 *px1 = x1;
00901 *px2 = x2;
00902 *px3 = x3;
00903 irplib_trace();
00904 } else if (is_complex) {
00905 *px1 = x1;
00906 irplib_trace();
00907 } else {
00908 *px1 = x3;
00909 irplib_trace();
00910 }
00911
00912 return is_complex;
00913 }
00914
00915
00929
00930 static void irplib_polynomial_solve_1d_31(double a, double Q,
00931 double * px1, double * px2,
00932 double * px3, cpl_boolean * pdbl1)
00933 {
00934
00935 const double sqrtQ = sqrt (Q);
00936
00937 double x1, x2, x3;
00938
00939 x2 = x1 = -sqrtQ - a / 3.0;
00940 x3 = 2.0 * sqrtQ - a / 3.0;
00941 if (pdbl1 != NULL) *pdbl1 = CPL_TRUE;
00942
00943 *px1 = x1;
00944 *px2 = x2;
00945 *px3 = x3;
00946
00947 irplib_trace();
00948 return;
00949 }
00950
00951
00966
00967 static void irplib_polynomial_solve_1d_32(double a, double c, double Q,
00968 double * px1, double * px2,
00969 double * px3, cpl_boolean * pdbl2)
00970 {
00971
00972 const double sqrtQ = sqrt (Q);
00973
00974 double x1 = DBL_MAX;
00975 double x2 = DBL_MAX;
00976 double x3 = DBL_MAX;
00977
00978 if (a > 0.0) {
00979
00980 x1 = -2.0 * sqrtQ - a / 3.0;
00981
00982
00983 x3 = x2 = -a < x1 ? -sqrt(fabs(c / x1)) : sqrt(fabs(c / x1));
00984 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00985 irplib_trace();
00986 } else if (a < 0.0) {
00987
00988 x3 = x2 = sqrtQ - a / 3.0;
00989 x1 = -c / (x2 * x2);
00990 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00991 irplib_trace();
00992 } else {
00993 x1 = -2.0 * sqrtQ;
00994 x3 = x2 = sqrtQ;
00995 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00996 irplib_trace();
00997 }
00998
00999 *px1 = x1;
01000 *px2 = x2;
01001 *px3 = x3;
01002
01003 return;
01004 }
01005
01006
01026
01027 static void irplib_polynomial_solve_1d_3c(double a, double c,
01028 double Q, double Q3,
01029 double R, double R2,
01030 double * px1,
01031 double * px2, double * px3,
01032 cpl_boolean * pis_c,
01033 cpl_boolean * pdbl2)
01034 {
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044 const double sgnR = (R >= 0 ? 1.0 : -1.0);
01045 const double A = -sgnR * pow (fabs (R) + sqrt (R2 - Q3), 1.0 / 3.0);
01046 const double B = Q / A;
01047
01048 double x1 = DBL_MAX;
01049 double x2 = DBL_MAX;
01050 double x3 = DBL_MAX;
01051 cpl_boolean is_complex = CPL_FALSE;
01052
01053 if (( A > -B && a > 0.0) || (A < -B && a < 0.0)) {
01054
01055
01056
01057 x2 = -0.5 * (A + B) - a / 3.0;
01058
01059 x3 = 0.5 * CPL_MATH_SQRT3 * fabs(A - B);
01060
01061 x1 = -c / (x2 * x2 + x3 * x3);
01062 irplib_trace();
01063 } else {
01064
01065 x1 = A + B - a / 3.0;
01066
01067 x3 = 0.5 * CPL_MATH_SQRT3 * fabs(A - B);
01068
01069 if (x3 > 0.0) {
01070
01071 x2 = -0.5 * (A + B) - a / 3.0;
01072 irplib_trace();
01073 } else {
01074
01075 x2 = -a < x1 ? -sqrt(fabs(c / x1)) : sqrt(fabs(c / x1));
01076 x2 = -0.5 * (A + B) - a / 3.0;
01077 x3 = 0.0;
01078 irplib_trace();
01079 }
01080 }
01081
01082 if (x3 > 0.0) {
01083 is_complex = CPL_TRUE;
01084 irplib_trace();
01085 } else {
01086
01087
01088 x3 = x2;
01089 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
01090 irplib_trace();
01091 }
01092
01093 *px1 = x1;
01094 *px2 = x2;
01095 *px3 = x3;
01096 *pis_c = is_complex;
01097
01098 return;
01099 }
01100
01101
01116
01117 static void irplib_polynomial_solve_1d_3r(double a, double c,
01118 double Q, double R,
01119 double * px1,
01120 double * px2, double * px3)
01121 {
01122
01123 const double sqrtQ = sqrt(Q);
01124 const double theta = acos (R / (Q * sqrtQ));
01125
01126
01127
01128
01129
01130 #define TR1 (-2.0 * sqrtQ * cos( theta / 3.0))
01131 #define TR2 (-2.0 * sqrtQ * cos((theta - CPL_MATH_2PI) / 3.0))
01132 #define TR3 (-2.0 * sqrtQ * cos((theta + CPL_MATH_2PI) / 3.0))
01133
01134
01135
01136
01137
01138
01139
01140
01141 double x1 = DBL_MAX;
01142 double x2 = DBL_MAX;
01143 double x3 = DBL_MAX;
01144
01145 if (a > 0.0) {
01146 x1 = TR1 - a / 3.0;
01147 if (TR2 > 0.0 && (TR2 + TR3) > 2.0 * a) {
01148
01149 x3 = TR3 - a / 3.0;
01150 x2 = -c / ( x1 * x3 );
01151 irplib_trace();
01152 } else {
01153
01154
01155
01156 x2 = TR2 - a / 3.0;
01157
01158 x3 = -c / ( x1 * x2 );
01159 irplib_trace();
01160 }
01161 } else if (a < 0.0) {
01162 x3 = TR3 - a / 3.0;
01163 if (TR2 < 0.0 && (TR1 + TR2) > 2.0 * a) {
01164 x1 = TR1 - a / 3.0;
01165 x2 = -c / ( x1 * x3 );
01166 irplib_trace();
01167 } else {
01168 x2 = TR2 - a / 3.0;
01169 x1 = -c / ( x2 * x3 );
01170 irplib_trace();
01171 }
01172 } else {
01173 x1 = TR1;
01174 x2 = TR2;
01175 x3 = TR3;
01176 irplib_trace();
01177 }
01178
01179 assert(x1 < x3);
01180
01181 if (x1 > x2) {
01182
01183
01184
01185
01186
01187
01188
01189 x1 = x2 = 0.5 * ( x1 + x2 );
01190 irplib_trace();
01191 } else if (x2 > x3) {
01192
01193
01194
01195
01196
01197
01198
01199 x3 = x2 = 0.5 * ( x2 + x3 );
01200 irplib_trace();
01201 }
01202
01203 *px1 = x1;
01204 *px2 = x2;
01205 *px3 = x3;
01206
01207 return;
01208 }
01209
01210
01228
01229 static cpl_error_code irplib_polynomial_solve_1d_4(double p4, double p3,
01230 double p2, double p1,
01231 double p0, int * preal,
01232 double * px1, double * px2,
01233 double * px3, double * px4)
01234 {
01235
01236
01237 const double a = (p2 - 0.375 * p3 * p3 / p4) / p4;
01238 const double b = (p1 - 0.5 * (p2 - 0.25 * p3 * p3 / p4 ) * p3 / p4 ) / p4;
01239 const double c =
01240 (p0 - 0.25 * (p1 - 0.25 * (p2 - 0.1875 * p3 * p3 / p4 ) * p3 / p4
01241 ) * p3 / p4 ) / p4;
01242
01243 double x1 = DBL_MAX;
01244 double x2 = DBL_MAX;
01245 double x3 = DBL_MAX;
01246 double x4 = DBL_MAX;
01247
01248 assert(preal != NULL );
01249 assert(px1 != NULL );
01250 assert(px2 != NULL );
01251 assert(px3 != NULL );
01252 assert(px4 != NULL );
01253
01254 *preal = 4;
01255
01256 if (c == 0.0) {
01257
01258
01259
01260 cpl_boolean dbl1, dbl2;
01261 const cpl_boolean is_real =
01262 !irplib_polynomial_solve_1d_3(1.0, 0.0, a, b, &x1, &x3, &x4,
01263 &dbl1, &dbl2);
01264
01265 x1 -= 0.25 * p3 / p4;
01266 x2 = -0.25 * p3 / p4;
01267 x3 -= 0.25 * p3 / p4;
01268 if (is_real) {
01269
01270 if (dbl2) {
01271 x4 = x3;
01272 assert( x1 <= x2);
01273 assert( x2 <= x3);
01274 } else {
01275 x4 -= 0.25 * p3 / p4;
01276
01277 if (x2 > x3) {
01278 IRPLIB_SWAP(x2, x3);
01279 }
01280 if (dbl1) {
01281 assert( x1 <= x2);
01282 assert( x2 <= x3);
01283 assert( x2 <= x4);
01284 } else {
01285 assert( x1 < x2);
01286 assert( x2 < x4);
01287 }
01288 }
01289 } else {
01290 *preal = 2;
01291
01292 if (x1 > x2) {
01293 assert( x3 <= x2 );
01294
01295 IRPLIB_SWAP(x1, x2);
01296 } else {
01297 assert( x3 >= x2 );
01298 }
01299 }
01300
01301 } else if (b == 0.0) {
01302
01303 double u1, u2;
01304 const cpl_boolean is_complex = irplib_polynomial_solve_1d_2(1.0, a, c,
01305 &u1, &u2);
01306
01307 if (is_complex) {
01308
01309 const double norm = sqrt(u1*u1 + u2*u2);
01310 const double v1 = sqrt(0.5*(norm+u1));
01311 const double v2 = u2 / sqrt(2.0*(norm+u1));
01312
01313
01314 x1 = -0.25 * p3 / p4 - v1;
01315 x3 = -0.25 * p3 / p4 + v1;
01316
01317 x4 = x2 = v2;
01318
01319 *preal = 0;
01320
01321 } else if (u1 >= 0.0) {
01322
01323 const double sv1 = sqrt(u1);
01324 const double sv2 = sqrt(u2);
01325
01326
01327 *preal = 4;
01328
01329 x1 = -0.25 * p3 / p4 - sv2;
01330 x2 = -0.25 * p3 / p4 - sv1;
01331 x3 = -0.25 * p3 / p4 + sv1;
01332 x4 = -0.25 * p3 / p4 + sv2;
01333 } else if (u2 < 0.0) {
01334
01335 const double sv1 = sqrt(-u2);
01336 const double sv2 = sqrt(-u1);
01337
01338
01339 *preal = 0;
01340
01341 x1 = x3 = -0.25 * p3 / p4;
01342
01343 x2 = sv1;
01344 x4 = sv2;
01345 } else {
01346
01347 const double sv1 = sqrt(-u1);
01348 const double sv2 = sqrt(u2);
01349
01350
01351 *preal = 2;
01352
01353 x1 = -0.25 * p3 / p4 - sv2;
01354 x2 = -0.25 * p3 / p4 + sv2;
01355
01356 x3 = -0.25 * p3 / p4;
01357 x4 = sv1;
01358 }
01359 } else {
01360
01361 const double q2 = -a;
01362 const double q1 = -4.0 * c;
01363 const double q0 = 4.0 * a * c - b * b;
01364 double u1, sqrtd, sqrtrd;
01365 double z1, z2, z3, z4;
01366
01367 cpl_boolean is_complex1, is_complex2;
01368
01369
01370
01371 (void)irplib_polynomial_solve_1d_3(1.0, q2, q1, q0, &u1, NULL, NULL,
01372 NULL, NULL);
01373
01374
01375 assert( u1 > a );
01376
01377 sqrtd = sqrt(u1 - a);
01378
01379 sqrtrd = 0.5 * b/sqrtd;
01380
01381 is_complex1 = irplib_polynomial_solve_1d_2(1.0, sqrtd, 0.5*u1 - sqrtrd,
01382 &z1, &z2);
01383
01384 is_complex2 = irplib_polynomial_solve_1d_2(1.0, -sqrtd, 0.5*u1 + sqrtrd,
01385 &z3, &z4);
01386
01387 z1 -= 0.25 * p3 / p4;
01388 z3 -= 0.25 * p3 / p4;
01389 if (!is_complex1) z2 -= 0.25 * p3 / p4;
01390 if (!is_complex2) z4 -= 0.25 * p3 / p4;
01391
01392 if (!is_complex1 && is_complex2) {
01393 *preal = 2;
01394 x1 = z1;
01395 x2 = z2;
01396 x3 = z3;
01397 x4 = z4;
01398 } else if (is_complex1 && !is_complex2) {
01399 *preal = 2;
01400 x1 = z3;
01401 x2 = z4;
01402 x3 = z1;
01403 x4 = z2;
01404 } else if (is_complex1 && is_complex2) {
01405 *preal = 0;
01406
01407 if (z1 < z3 || (z1 == z3 && z2 <= z4)) {
01408 x1 = z1;
01409 x2 = z2;
01410 x3 = z3;
01411 x4 = z4;
01412 } else {
01413 x1 = z3;
01414 x2 = z4;
01415 x3 = z1;
01416 x4 = z2;
01417 }
01418 } else {
01419 *preal = 4;
01420
01421 if (z3 >= z2) {
01422 x1 = z1;
01423 x2 = z2;
01424 x3 = z3;
01425 x4 = z4;
01426 } else if (z4 <= z1) {
01427 x1 = z3;
01428 x2 = z4;
01429 x3 = z1;
01430 x4 = z2;
01431 } else if (z2 > z4) {
01432 x1 = z3;
01433 x2 = z1;
01434 x3 = z4;
01435 x4 = z2;
01436 } else {
01437 x1 = z1;
01438 x2 = z3;
01439 x3 = z2;
01440 x4 = z4;
01441 }
01442 }
01443 }
01444
01445 *px1 = x1;
01446 *px2 = x2;
01447 *px3 = x3;
01448 *px4 = x4;
01449
01450 return CPL_ERROR_NONE;
01451 }
01452
01453 #ifdef IPRLIB_POLYNOMIAL_USE_MONOMIAL_ROOT
01454
01462
01463 static double irplib_polynomial_depress_1d(cpl_polynomial * self)
01464 {
01465
01466 const int degree = cpl_polynomial_get_degree(self);
01467 const int nc1 = degree - 1;
01468 const double an = cpl_polynomial_get_coeff(self, °ree);
01469 const double an1 = cpl_polynomial_get_coeff(self, &nc1);
01470 double rmean;
01471 int i;
01472
01473
01474 cpl_ensure(degree > 0, CPL_ERROR_DATA_NOT_FOUND, 0.0);
01475
01476 assert( an != 0.0 );
01477
01478 rmean = -an1/(an * (double)degree);
01479
01480 if (rmean != 0.0) {
01481
01482 cpl_polynomial_shift_1d(self, rmean);
01483
01484 cpl_polynomial_set_coeff(self, &nc1, 0.0);
01485
01486 }
01487
01488
01489 for (i = 0; i < degree-1; i++) {
01490 const double ai = cpl_polynomial_get_coeff(self, &i) / an;
01491 cpl_polynomial_set_coeff(self, &i, ai);
01492 }
01493
01494 cpl_polynomial_set_coeff(self, °ree, 1.0);
01495
01496 return rmean;
01497 }
01498 #endif
01499
01500
01515
01516 static
01517 cpl_error_code irplib_polynomial_divide_1d_root(cpl_polynomial * p, double r,
01518 double * pres)
01519 {
01520
01521 const int n = cpl_polynomial_get_degree(p);
01522 double sum;
01523 int i;
01524
01525
01526 cpl_ensure_code(p != NULL, CPL_ERROR_NULL_INPUT);
01527 cpl_ensure_code(cpl_polynomial_get_dimension(p) == 1,
01528 CPL_ERROR_INVALID_TYPE);
01529 cpl_ensure_code(n > 0, CPL_ERROR_DATA_NOT_FOUND);
01530
01531 sum = cpl_polynomial_get_coeff(p, &n);
01532 cpl_polynomial_set_coeff(p, &n, 0.0);
01533
01534 for (i = n-1; i >= 0; i--) {
01535 const double coeff = cpl_polynomial_get_coeff(p, &i);
01536
01537 cpl_polynomial_set_coeff(p, &i, sum);
01538
01539 sum = coeff + r * sum;
01540
01541 }
01542
01543 if (pres != NULL) *pres = sum;
01544
01545 return CPL_ERROR_NONE;
01546 }