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, 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 #if defined CPL_VERSION_CODE && CPL_VERSION_CODE > CPL_VERSION(5, 92, 0)
00116 #else
00117
00118
00133
00134 cpl_error_code irplib_polynomial_add(cpl_polynomial * self,
00135 const cpl_polynomial * first,
00136 const cpl_polynomial * second)
00137 {
00138 cpl_size degree0 = cpl_polynomial_get_degree(self);
00139 const cpl_size degree1 = cpl_polynomial_get_degree(first);
00140 const cpl_size degree2 = cpl_polynomial_get_degree(second);
00141 const cpl_size maxdeg = degree1 > degree2 ? degree1 : degree2;
00142
00143
00144 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00145 cpl_ensure_code(first != NULL, CPL_ERROR_NULL_INPUT);
00146 cpl_ensure_code(second != NULL, CPL_ERROR_NULL_INPUT);
00147
00148 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00149 cpl_polynomial_get_dimension(first),
00150 CPL_ERROR_INCOMPATIBLE_INPUT);
00151 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00152 cpl_polynomial_get_dimension(second),
00153 CPL_ERROR_INCOMPATIBLE_INPUT);
00154
00155
00156 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00157 CPL_ERROR_UNSUPPORTED_MODE);
00158
00159 if (degree0 < maxdeg) {
00160 degree0 = maxdeg;
00161 } else {
00162
00163 for (; degree0 > maxdeg; degree0--) {
00164 cpl_polynomial_set_coeff(self, °ree0, 0.0);
00165 }
00166 }
00167
00168
00169
00170 for (; degree0 >= 0; degree0--) {
00171 const double val1 = cpl_polynomial_get_coeff(first, °ree0);
00172 const double val2 = cpl_polynomial_get_coeff(second, °ree0);
00173 cpl_polynomial_set_coeff(self, °ree0, val1 + val2);
00174 }
00175
00176 return CPL_ERROR_NONE;
00177 }
00178
00179
00194
00195 cpl_error_code irplib_polynomial_subtract(cpl_polynomial * self,
00196 const cpl_polynomial * first,
00197 const cpl_polynomial * second)
00198 {
00199 cpl_size degree0 = cpl_polynomial_get_degree(self);
00200 const cpl_size degree1 = cpl_polynomial_get_degree(first);
00201 const cpl_size degree2 = cpl_polynomial_get_degree(second);
00202 const cpl_size maxdeg = degree1 > degree2 ? degree1 : degree2;
00203
00204
00205 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00206 cpl_ensure_code(first != NULL, CPL_ERROR_NULL_INPUT);
00207 cpl_ensure_code(second != NULL, CPL_ERROR_NULL_INPUT);
00208
00209 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00210 cpl_polynomial_get_dimension(first),
00211 CPL_ERROR_INCOMPATIBLE_INPUT);
00212 cpl_ensure_code(cpl_polynomial_get_dimension(self) ==
00213 cpl_polynomial_get_dimension(second),
00214 CPL_ERROR_INCOMPATIBLE_INPUT);
00215
00216
00217 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00218 CPL_ERROR_UNSUPPORTED_MODE);
00219
00220 if (degree0 < maxdeg) {
00221 degree0 = maxdeg;
00222 } else {
00223
00224 for (; degree0 > maxdeg; degree0--) {
00225 cpl_polynomial_set_coeff(self, °ree0, 0.0);
00226 }
00227 }
00228
00229
00230
00231 for (; degree0 >= 0; degree0--) {
00232 const double val1 = cpl_polynomial_get_coeff(first, °ree0);
00233 const double val2 = cpl_polynomial_get_coeff(second, °ree0);
00234 cpl_polynomial_set_coeff(self, °ree0, val1 - val2);
00235 }
00236
00237 return CPL_ERROR_NONE;
00238 }
00239
00240
00252
00253 cpl_error_code irplib_polynomial_multiply_scalar(cpl_polynomial * self,
00254 const cpl_polynomial * other,
00255 double factor)
00256 {
00257
00258 const cpl_size maxdeg = cpl_polynomial_get_degree(other);
00259 const cpl_size zerodeg = cpl_polynomial_get_degree(self);
00260 cpl_size degree;
00261
00262 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00263 cpl_ensure_code(other != NULL, CPL_ERROR_NULL_INPUT);
00264
00265 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00266 CPL_ERROR_UNSUPPORTED_MODE);
00267 cpl_ensure_code(cpl_polynomial_get_dimension(other) == 1,
00268 CPL_ERROR_UNSUPPORTED_MODE);
00269
00270 for (degree = 0; degree <= maxdeg; degree++) {
00271 const double val = factor * cpl_polynomial_get_coeff(other, °ree);
00272 cpl_polynomial_set_coeff(self, °ree, val);
00273 }
00274
00275
00276 for (; degree <= zerodeg; degree++) {
00277 cpl_polynomial_set_coeff(self, &zerodeg, 0.0);
00278 }
00279
00280 return CPL_ERROR_NONE;
00281 }
00282 #endif
00283
00309
00310 cpl_error_code irplib_polynomial_solve_1d_all(const cpl_polynomial * self,
00311 cpl_vector * roots,
00312 cpl_size * preal)
00313 {
00314
00315 cpl_error_code error = CPL_ERROR_NONE;
00316 cpl_polynomial * p;
00317
00318 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00319 cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
00320 cpl_ensure_code(preal != NULL, CPL_ERROR_NULL_INPUT);
00321 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00322 CPL_ERROR_INVALID_TYPE);
00323 cpl_ensure_code(cpl_polynomial_get_degree(self) > 0,
00324 CPL_ERROR_DATA_NOT_FOUND);
00325 cpl_ensure_code(cpl_polynomial_get_degree(self) ==
00326 cpl_vector_get_size(roots), CPL_ERROR_INCOMPATIBLE_INPUT);
00327
00328 *preal = 0;
00329
00330 p = cpl_polynomial_duplicate(self);
00331
00332 error = irplib_polynomial_solve_1d_nonzero(p, roots, preal);
00333
00334 cpl_polynomial_delete(p);
00335
00336 return error;
00337
00338 }
00339
00342
00368
00369 static cpl_error_code irplib_polynomial_solve_1d_nonzero(cpl_polynomial * self,
00370 cpl_vector * roots,
00371 cpl_size * preal)
00372 {
00373 cpl_error_code error = CPL_ERROR_NONE;
00374 const cpl_size ncoeffs = 1 + cpl_polynomial_get_degree(self);
00375
00376 cpl_ensure_code(self != NULL, CPL_ERROR_NULL_INPUT);
00377 cpl_ensure_code(roots != NULL, CPL_ERROR_NULL_INPUT);
00378 cpl_ensure_code(preal != NULL, CPL_ERROR_NULL_INPUT);
00379 cpl_ensure_code(cpl_polynomial_get_dimension(self) == 1,
00380 CPL_ERROR_INVALID_TYPE);
00381 cpl_ensure_code(ncoeffs > 1, CPL_ERROR_DATA_NOT_FOUND);
00382 cpl_ensure_code(*preal >= 0, CPL_ERROR_ILLEGAL_INPUT);
00383 cpl_ensure_code(ncoeffs + *preal == 1+cpl_vector_get_size(roots),
00384 CPL_ERROR_INCOMPATIBLE_INPUT);
00385
00386 switch (ncoeffs) {
00387
00388 case 2 : {
00389 const cpl_size i1 = 1;
00390 const cpl_size i0 = 0;
00391 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00392 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00393
00394 cpl_vector_set(roots, (*preal)++, -p0/p1);
00395 break;
00396 }
00397 case 3 : {
00398 const cpl_size i2 = 2;
00399 const cpl_size i1 = 1;
00400 const cpl_size i0 = 0;
00401 const double p2 = cpl_polynomial_get_coeff(self, &i2);
00402 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00403 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00404 double x1, x2;
00405
00406 if (irplib_polynomial_solve_1d_2(p2, p1, p0, &x1, &x2)) {
00407
00408 cpl_vector_set(roots, (*preal) , x1);
00409 cpl_vector_set(roots, (*preal)+1, x2);
00410 } else {
00411 cpl_vector_set(roots, (*preal)++, x1);
00412 cpl_vector_set(roots, (*preal)++, x2);
00413 }
00414 break;
00415 }
00416 case 4 : {
00417 const cpl_size i3 = 3;
00418 const cpl_size i2 = 2;
00419 const cpl_size i1 = 1;
00420 const cpl_size i0 = 0;
00421 const double p3 = cpl_polynomial_get_coeff(self, &i3);
00422 const double p2 = cpl_polynomial_get_coeff(self, &i2);
00423 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00424 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00425 double x1, x2, x3;
00426
00427 if (irplib_polynomial_solve_1d_3(p3, p2, p1, p0, &x1, &x2, &x3,
00428 NULL, NULL)) {
00429 cpl_vector_set(roots, (*preal)++, x1);
00430
00431 cpl_vector_set(roots, (*preal) , x2);
00432 cpl_vector_set(roots, (*preal)+1, x3);
00433 } else {
00434 cpl_vector_set(roots, (*preal)++, x1);
00435 cpl_vector_set(roots, (*preal)++, x2);
00436 cpl_vector_set(roots, (*preal)++, x3);
00437 }
00438 break;
00439 }
00440 case 5 : {
00441 const cpl_size i4 = 4;
00442 const cpl_size i3 = 3;
00443 const cpl_size i2 = 2;
00444 const cpl_size i1 = 1;
00445 const cpl_size i0 = 0;
00446 const double p4 = cpl_polynomial_get_coeff(self, &i4);
00447 const double p3 = cpl_polynomial_get_coeff(self, &i3);
00448 const double p2 = cpl_polynomial_get_coeff(self, &i2);
00449 const double p1 = cpl_polynomial_get_coeff(self, &i1);
00450 const double p0 = cpl_polynomial_get_coeff(self, &i0);
00451 double x1, x2, x3, x4;
00452 cpl_size nreal;
00453
00454 error = irplib_polynomial_solve_1d_4(p4, p3, p2, p1, p0, &nreal,
00455 &x1, &x2, &x3, &x4);
00456 if (!error) {
00457 cpl_vector_set(roots, (*preal) , x1);
00458 cpl_vector_set(roots, (*preal)+1, x2);
00459 cpl_vector_set(roots, (*preal)+2, x3);
00460 cpl_vector_set(roots, (*preal)+3, x4);
00461
00462 *preal += nreal;
00463 }
00464 break;
00465 }
00466
00467 default: {
00468
00469
00470 #ifndef IPRLIB_POLYNOMIAL_USE_MONOMIAL_ROOT
00471 const cpl_size n0 = ncoeffs-1;
00472 const double pn0 = cpl_polynomial_get_coeff(self, &n0);
00473 const cpl_size n1 = ncoeffs-2;
00474 const double pn1 = cpl_polynomial_get_coeff(self, &n1);
00475
00476
00477 const double rmean = -pn1 / (pn0 * n0);
00478 double root = rmean;
00479 #else
00480
00481 cpl_polynomial * copy = cpl_polynomial_duplicate(self);
00482 const cpl_size i0 = 0;
00483 const double rmean = irplib_polynomial_depress_1d(copy);
00484 const double c0 = cpl_polynomial_get_coeff(copy, &i0);
00485 double root = rmean + ((n0&1) && c0 < 0.0 ? -1.0 : 1.0)
00486 * pow(fabs(c0), 1.0/n0);
00487
00488 cpl_polynomial_delete(copy);
00489 #endif
00490
00491 error = cpl_polynomial_solve_1d(self, root, &root, 1);
00492
00493 if (!error) {
00494
00495 cpl_vector_set(roots, (*preal)++, root);
00496
00497 irplib_polynomial_divide_1d_root(self, root, NULL);
00498
00499 error = irplib_polynomial_solve_1d_nonzero(self, roots, preal);
00500
00501 if (!error && *preal > 1) {
00502
00503
00504
00505
00506 cpl_vector * reals = cpl_vector_wrap(*preal,
00507 cpl_vector_get_data(roots));
00508 cpl_vector_sort(reals, 1);
00509 (void)cpl_vector_unwrap(reals);
00510 }
00511 }
00512 break;
00513 }
00514 }
00515
00516 return error;
00517 }
00518
00519
00531
00532 static cpl_boolean irplib_polynomial_solve_1d_2(double p2, double p1, double p0,
00533 double * px1,
00534 double * px2) {
00535
00536 const double sqrtD = sqrt(fabs(p1 * p1 - 4.0 * p2 * p0));
00537 cpl_boolean is_complex = CPL_FALSE;
00538 double x1 = -0.5 * p1 / p2;
00539 double x2;
00540
00541
00542 double res0 = irplib_polynomial_eval_2_max(p2, p1, p0, CPL_FALSE, x1, x1);
00543 double res;
00544
00545 assert(px1 != NULL );
00546 assert(px2 != NULL );
00547
00548 *px2 = *px1 = x1;
00549
00550
00551
00552
00553 if (p1 > 0.0) {
00554 x1 = -0.5 * (p1 + sqrtD);
00555 irplib_trace();
00556 } else {
00557 x1 = -0.5 * (p1 - sqrtD);
00558 irplib_trace();
00559 }
00560
00561
00562 x2 = p0 / x1;
00563 x1 /= p2;
00564
00565 res = irplib_polynomial_eval_2_max(p2, p1, p0, CPL_FALSE, x1, x2);
00566
00567 if (res < res0) {
00568 res0 = res;
00569 if (x2 > x1) {
00570 *px1 = x1;
00571 *px2 = x2;
00572 irplib_trace();
00573 } else {
00574 *px1 = x2;
00575 *px2 = x1;
00576 irplib_trace();
00577 }
00578 }
00579
00580
00581
00582 x1 = -0.5 * p1 / p2;
00583 x2 = 0.5 * sqrtD / fabs(p2);
00584
00585 res = irplib_polynomial_eval_2_max(p2, p1, p0, CPL_TRUE, x1, x2);
00586
00587 if (res < res0) {
00588 *px1 = x1;
00589 *px2 = x2;
00590 is_complex = CPL_TRUE;
00591 irplib_trace();
00592 }
00593
00594 return is_complex;
00595
00596 }
00597
00598
00599
00612
00613 static double irplib_polynomial_eval_2_max(double p2, double p1, double p0,
00614 cpl_boolean is_c,
00615 double x1, double x2)
00616 {
00617 double res;
00618
00619 if (is_c) {
00620 res = fabs(p0 + x1 * (p1 + x1 * p2) - p2 * x2 * x2);
00621 irplib_trace();
00622 } else {
00623 const double r1 = fabs(p0 + x1 * (p1 + x1 * p2));
00624 const double r2 = fabs(p0 + x2 * (p1 + x2 * p2));
00625
00626 res = r1 > r2 ? r1 : r2;
00627 irplib_trace();
00628 }
00629
00630 return res;
00631 }
00632
00633
00634
00649
00650 static double irplib_polynomial_eval_3_max(double p3, double p2,
00651 double p1, double p0,
00652 cpl_boolean is_c,
00653 double x1, double x2, double x3)
00654 {
00655 const double r1 = fabs(p0 + x1 * (p1 + x1 * (p2 + x1 * p3)));
00656 double res;
00657
00658 if (is_c) {
00659 const double r2 = fabs(p0 + x2 * (p1 + x2 * (p2 + x2 * p3))
00660 - x3 * x3 * ( 3.0 * p3 * x2 + p2));
00661
00662 res = r1 > r2 ? r1 : r2;
00663 irplib_trace();
00664 } else {
00665 const double r2 = fabs(p0 + x2 * (p1 + x2 * (p2 + x2 * p3)));
00666 const double r3 = fabs(p0 + x3 * (p1 + x3 * (p2 + x3 * p3)));
00667 res = r1 > r2 ? (r1 > r3 ? r1 : r3) : (r2 > r3 ? r2 : r3);
00668 irplib_trace();
00669 }
00670
00671
00672
00673 return res;
00674 }
00675
00676
00677
00696
00697 static cpl_boolean irplib_polynomial_solve_1d_3(double p3, double p2, double p1,
00698 double p0,
00699 double * px1,
00700 double * px2,
00701 double * px3,
00702 cpl_boolean * pdbl1,
00703 cpl_boolean * pdbl2) {
00704 cpl_boolean is_complex = CPL_FALSE;
00705 const double a = p2/p3;
00706 const double b = p1/p3;
00707 const double c = p0/p3;
00708
00709 const double q = (a * a - 3.0 * b);
00710 const double r = (a * (2.0 * a * a - 9.0 * b) + 27.0 * c);
00711
00712 const double Q = q / 9.0;
00713 const double R = r / 54.0;
00714
00715 const double Q3 = Q * Q * Q;
00716 const double R2 = R * R;
00717
00718 double x1 = DBL_MAX;
00719 double x2 = DBL_MAX;
00720 double x3 = DBL_MAX;
00721 double xx1 = DBL_MAX;
00722 double xx2 = DBL_MAX;
00723 double xx3 = DBL_MAX;
00724
00725 double resx = DBL_MAX;
00726 double res = DBL_MAX;
00727 cpl_boolean is_first = CPL_TRUE;
00728
00729 cpl_boolean dbl2;
00730
00731
00732 assert(px1 != NULL );
00733
00734 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00735 if (pdbl2 != NULL) *pdbl2 = CPL_FALSE;
00736
00737 dbl2 = CPL_FALSE;
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747 if ((R2 >= Q3 && R != 0.0) || R2 > Q3) {
00748
00749 cpl_boolean is_c = CPL_FALSE;
00750
00751 irplib_polynomial_solve_1d_3c(a, c, Q, Q3, R, R2, &x1, &x2, &x3,
00752 &is_c, &dbl2);
00753
00754
00755 res = resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, is_c,
00756 x1, x2, x3);
00757
00758 is_first = CPL_FALSE;
00759
00760 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00761 if (!is_c && pdbl2 != NULL) *pdbl2 = dbl2;
00762 is_complex = is_c;
00763 irplib_trace();
00764
00765 }
00766
00767 if (Q > 0.0 && fabs(R / (Q * sqrt(Q))) <= 1.0) {
00768
00769
00770
00771
00772
00773
00774 irplib_polynomial_solve_1d_3r(a, c, Q, R, &xx1, &xx2, &xx3);
00775
00776 resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, CPL_FALSE,
00777 xx1, xx2, xx3);
00778
00779 if (is_first || (dbl2 ? resx < res : resx <= res)) {
00780 is_first = CPL_FALSE;
00781 res = resx;
00782 x1 = xx1;
00783 x2 = xx2;
00784 x3 = xx3;
00785 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00786 if (pdbl2 != NULL) *pdbl2 = CPL_FALSE;
00787 is_complex = CPL_FALSE;
00788 irplib_trace();
00789 }
00790 }
00791
00792 if (Q >= 0) {
00793 cpl_boolean dbl1 = CPL_FALSE;
00794
00795
00796 irplib_polynomial_solve_1d_32(a, c, Q, &xx1, &xx2, &xx3, &dbl2);
00797
00798 resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, CPL_FALSE,
00799 xx1, xx2, xx3);
00800
00801
00802
00803
00804
00805 if (is_first || resx <= res) {
00806 is_first = CPL_FALSE;
00807 res = resx;
00808 x1 = xx1;
00809 x2 = xx2;
00810 x3 = xx3;
00811 if (pdbl1 != NULL) *pdbl1 = CPL_FALSE;
00812 if (pdbl2 != NULL) *pdbl2 = dbl2;
00813 is_complex = CPL_FALSE;
00814 irplib_trace();
00815 }
00816
00817
00818
00819
00820
00821 irplib_polynomial_solve_1d_31(a, Q, &xx1, &xx2, &xx3, &dbl1);
00822
00823 resx = irplib_polynomial_eval_3_max(p3, p2, p1, p0, CPL_FALSE,
00824 xx1, xx2, xx3);
00825
00826 if (resx <= res) {
00827 is_first = CPL_FALSE;
00828 res = resx;
00829 x1 = xx1;
00830 x2 = xx2;
00831 x3 = xx3;
00832 if (pdbl1 != NULL) *pdbl1 = dbl1;
00833 if (pdbl2 != NULL) *pdbl2 = CPL_FALSE;
00834 is_complex = CPL_FALSE;
00835 irplib_trace();
00836 }
00837
00838 }
00839
00840 if (px2 != NULL && px3 != NULL) {
00841 *px1 = x1;
00842 *px2 = x2;
00843 *px3 = x3;
00844 irplib_trace();
00845 } else if (is_complex) {
00846 *px1 = x1;
00847 irplib_trace();
00848 } else {
00849 *px1 = x3;
00850 irplib_trace();
00851 }
00852
00853 return is_complex;
00854 }
00855
00856
00870
00871 static void irplib_polynomial_solve_1d_31(double a, double Q,
00872 double * px1, double * px2,
00873 double * px3, cpl_boolean * pdbl1)
00874 {
00875
00876 const double sqrtQ = sqrt (Q);
00877
00878 double x1, x2, x3;
00879
00880 x2 = x1 = -sqrtQ - a / 3.0;
00881 x3 = 2.0 * sqrtQ - a / 3.0;
00882 if (pdbl1 != NULL) *pdbl1 = CPL_TRUE;
00883
00884 *px1 = x1;
00885 *px2 = x2;
00886 *px3 = x3;
00887
00888 irplib_trace();
00889 return;
00890 }
00891
00892
00907
00908 static void irplib_polynomial_solve_1d_32(double a, double c, double Q,
00909 double * px1, double * px2,
00910 double * px3, cpl_boolean * pdbl2)
00911 {
00912
00913 const double sqrtQ = sqrt (Q);
00914
00915 double x1 = DBL_MAX;
00916 double x2 = DBL_MAX;
00917 double x3 = DBL_MAX;
00918
00919 if (a > 0.0) {
00920
00921 x1 = -2.0 * sqrtQ - a / 3.0;
00922
00923
00924 x3 = x2 = -a < x1 ? -sqrt(fabs(c / x1)) : sqrt(fabs(c / x1));
00925 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00926 irplib_trace();
00927 } else if (a < 0.0) {
00928
00929 x3 = x2 = sqrtQ - a / 3.0;
00930 x1 = -c / (x2 * x2);
00931 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00932 irplib_trace();
00933 } else {
00934 x1 = -2.0 * sqrtQ;
00935 x3 = x2 = sqrtQ;
00936 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
00937 irplib_trace();
00938 }
00939
00940 *px1 = x1;
00941 *px2 = x2;
00942 *px3 = x3;
00943
00944 return;
00945 }
00946
00947
00967
00968 static void irplib_polynomial_solve_1d_3c(double a, double c,
00969 double Q, double Q3,
00970 double R, double R2,
00971 double * px1,
00972 double * px2, double * px3,
00973 cpl_boolean * pis_c,
00974 cpl_boolean * pdbl2)
00975 {
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985 const double sgnR = (R >= 0 ? 1.0 : -1.0);
00986 const double A = -sgnR * pow (fabs (R) + sqrt (R2 - Q3), 1.0 / 3.0);
00987 const double B = Q / A;
00988
00989 double x1 = DBL_MAX;
00990 double x2 = DBL_MAX;
00991 double x3 = DBL_MAX;
00992 cpl_boolean is_complex = CPL_FALSE;
00993
00994 if (( A > -B && a > 0.0) || (A < -B && a < 0.0)) {
00995
00996
00997
00998 x2 = -0.5 * (A + B) - a / 3.0;
00999
01000 x3 = 0.5 * CPL_MATH_SQRT3 * fabs(A - B);
01001
01002 x1 = -c / (x2 * x2 + x3 * x3);
01003 irplib_trace();
01004 } else {
01005
01006 x1 = A + B - a / 3.0;
01007
01008 x3 = 0.5 * CPL_MATH_SQRT3 * fabs(A - B);
01009
01010 if (x3 > 0.0) {
01011
01012 x2 = -0.5 * (A + B) - a / 3.0;
01013 irplib_trace();
01014 } else {
01015
01016 x2 = -a < x1 ? -sqrt(fabs(c / x1)) : sqrt(fabs(c / x1));
01017 x2 = -0.5 * (A + B) - a / 3.0;
01018 x3 = 0.0;
01019 irplib_trace();
01020 }
01021 }
01022
01023 if (x3 > 0.0) {
01024 is_complex = CPL_TRUE;
01025 irplib_trace();
01026 } else {
01027
01028
01029 x3 = x2;
01030 if (pdbl2 != NULL) *pdbl2 = CPL_TRUE;
01031 irplib_trace();
01032 }
01033
01034 *px1 = x1;
01035 *px2 = x2;
01036 *px3 = x3;
01037 *pis_c = is_complex;
01038
01039 return;
01040 }
01041
01042
01057
01058 static void irplib_polynomial_solve_1d_3r(double a, double c,
01059 double Q, double R,
01060 double * px1,
01061 double * px2, double * px3)
01062 {
01063
01064 const double sqrtQ = sqrt(Q);
01065 const double theta = acos (R / (Q * sqrtQ));
01066
01067
01068
01069
01070
01071 #define TR1 (-2.0 * sqrtQ * cos( theta / 3.0))
01072 #define TR2 (-2.0 * sqrtQ * cos((theta - CPL_MATH_2PI) / 3.0))
01073 #define TR3 (-2.0 * sqrtQ * cos((theta + CPL_MATH_2PI) / 3.0))
01074
01075
01076
01077
01078
01079
01080
01081
01082 double x1 = DBL_MAX;
01083 double x2 = DBL_MAX;
01084 double x3 = DBL_MAX;
01085
01086 if (a > 0.0) {
01087 x1 = TR1 - a / 3.0;
01088 if (TR2 > 0.0 && (TR2 + TR3) > 2.0 * a) {
01089
01090 x3 = TR3 - a / 3.0;
01091 x2 = -c / ( x1 * x3 );
01092 irplib_trace();
01093 } else {
01094
01095
01096
01097 x2 = TR2 - a / 3.0;
01098
01099 x3 = -c / ( x1 * x2 );
01100 irplib_trace();
01101 }
01102 } else if (a < 0.0) {
01103 x3 = TR3 - a / 3.0;
01104 if (TR2 < 0.0 && (TR1 + TR2) > 2.0 * a) {
01105 x1 = TR1 - a / 3.0;
01106 x2 = -c / ( x1 * x3 );
01107 irplib_trace();
01108 } else {
01109 x2 = TR2 - a / 3.0;
01110 x1 = -c / ( x2 * x3 );
01111 irplib_trace();
01112 }
01113 } else {
01114 x1 = TR1;
01115 x2 = TR2;
01116 x3 = TR3;
01117 irplib_trace();
01118 }
01119
01120 assert(x1 < x3);
01121
01122 if (x1 > x2) {
01123
01124
01125
01126
01127
01128
01129
01130 x1 = x2 = 0.5 * ( x1 + x2 );
01131 irplib_trace();
01132 } else if (x2 > x3) {
01133
01134
01135
01136
01137
01138
01139
01140 x3 = x2 = 0.5 * ( x2 + x3 );
01141 irplib_trace();
01142 }
01143
01144 *px1 = x1;
01145 *px2 = x2;
01146 *px3 = x3;
01147
01148 return;
01149 }
01150
01151
01169
01170 static cpl_error_code irplib_polynomial_solve_1d_4(double p4, double p3,
01171 double p2, double p1,
01172 double p0, cpl_size * preal,
01173 double * px1, double * px2,
01174 double * px3, double * px4)
01175 {
01176
01177
01178 const double a = (p2 - 0.375 * p3 * p3 / p4) / p4;
01179 const double b = (p1 - 0.5 * (p2 - 0.25 * p3 * p3 / p4 ) * p3 / p4 ) / p4;
01180 const double c =
01181 (p0 - 0.25 * (p1 - 0.25 * (p2 - 0.1875 * p3 * p3 / p4 ) * p3 / p4
01182 ) * p3 / p4 ) / p4;
01183
01184 double x1 = DBL_MAX;
01185 double x2 = DBL_MAX;
01186 double x3 = DBL_MAX;
01187 double x4 = DBL_MAX;
01188
01189 assert(preal != NULL );
01190 assert(px1 != NULL );
01191 assert(px2 != NULL );
01192 assert(px3 != NULL );
01193 assert(px4 != NULL );
01194
01195 *preal = 4;
01196
01197 if (c == 0.0) {
01198
01199
01200
01201 cpl_boolean dbl1, dbl2;
01202 const cpl_boolean is_real =
01203 !irplib_polynomial_solve_1d_3(1.0, 0.0, a, b, &x1, &x3, &x4,
01204 &dbl1, &dbl2);
01205
01206 x1 -= 0.25 * p3 / p4;
01207 x2 = -0.25 * p3 / p4;
01208 x3 -= 0.25 * p3 / p4;
01209 if (is_real) {
01210
01211 if (dbl2) {
01212 x4 = x3;
01213 assert( x1 <= x2);
01214 assert( x2 <= x3);
01215 } else {
01216 x4 -= 0.25 * p3 / p4;
01217
01218 if (x2 > x3) {
01219 IRPLIB_SWAP(x2, x3);
01220 }
01221 if (dbl1) {
01222 assert( x1 <= x2);
01223 assert( x2 <= x3);
01224 assert( x2 <= x4);
01225 } else {
01226 assert( x1 < x2);
01227 assert( x2 < x4);
01228 }
01229 }
01230 } else {
01231 *preal = 2;
01232
01233 if (x1 > x2) {
01234 assert( x3 <= x2 );
01235
01236 IRPLIB_SWAP(x1, x2);
01237 } else {
01238 assert( x3 >= x2 );
01239 }
01240 }
01241
01242 } else if (b == 0.0) {
01243
01244 double u1, u2;
01245 const cpl_boolean is_complex = irplib_polynomial_solve_1d_2(1.0, a, c,
01246 &u1, &u2);
01247
01248 if (is_complex) {
01249
01250 const double norm = sqrt(u1*u1 + u2*u2);
01251 const double v1 = sqrt(0.5*(norm+u1));
01252 const double v2 = u2 / sqrt(2.0*(norm+u1));
01253
01254
01255 x1 = -0.25 * p3 / p4 - v1;
01256 x3 = -0.25 * p3 / p4 + v1;
01257
01258 x4 = x2 = v2;
01259
01260 *preal = 0;
01261
01262 } else if (u1 >= 0.0) {
01263
01264 const double sv1 = sqrt(u1);
01265 const double sv2 = sqrt(u2);
01266
01267
01268 *preal = 4;
01269
01270 x1 = -0.25 * p3 / p4 - sv2;
01271 x2 = -0.25 * p3 / p4 - sv1;
01272 x3 = -0.25 * p3 / p4 + sv1;
01273 x4 = -0.25 * p3 / p4 + sv2;
01274 } else if (u2 < 0.0) {
01275
01276 const double sv1 = sqrt(-u2);
01277 const double sv2 = sqrt(-u1);
01278
01279
01280 *preal = 0;
01281
01282 x1 = x3 = -0.25 * p3 / p4;
01283
01284 x2 = sv1;
01285 x4 = sv2;
01286 } else {
01287
01288 const double sv1 = sqrt(-u1);
01289 const double sv2 = sqrt(u2);
01290
01291
01292 *preal = 2;
01293
01294 x1 = -0.25 * p3 / p4 - sv2;
01295 x2 = -0.25 * p3 / p4 + sv2;
01296
01297 x3 = -0.25 * p3 / p4;
01298 x4 = sv1;
01299 }
01300 } else {
01301
01302 const double q2 = -a;
01303 const double q1 = -4.0 * c;
01304 const double q0 = 4.0 * a * c - b * b;
01305 double u1, sqrtd, sqrtrd;
01306 double z1, z2, z3, z4;
01307
01308 cpl_boolean is_complex1, is_complex2;
01309
01310
01311
01312 (void)irplib_polynomial_solve_1d_3(1.0, q2, q1, q0, &u1, NULL, NULL,
01313 NULL, NULL);
01314
01315
01316 assert( u1 > a );
01317
01318 sqrtd = sqrt(u1 - a);
01319
01320 sqrtrd = 0.5 * b/sqrtd;
01321
01322 is_complex1 = irplib_polynomial_solve_1d_2(1.0, sqrtd, 0.5*u1 - sqrtrd,
01323 &z1, &z2);
01324
01325 is_complex2 = irplib_polynomial_solve_1d_2(1.0, -sqrtd, 0.5*u1 + sqrtrd,
01326 &z3, &z4);
01327
01328 z1 -= 0.25 * p3 / p4;
01329 z3 -= 0.25 * p3 / p4;
01330 if (!is_complex1) z2 -= 0.25 * p3 / p4;
01331 if (!is_complex2) z4 -= 0.25 * p3 / p4;
01332
01333 if (!is_complex1 && is_complex2) {
01334 *preal = 2;
01335 x1 = z1;
01336 x2 = z2;
01337 x3 = z3;
01338 x4 = z4;
01339 } else if (is_complex1 && !is_complex2) {
01340 *preal = 2;
01341 x1 = z3;
01342 x2 = z4;
01343 x3 = z1;
01344 x4 = z2;
01345 } else if (is_complex1 && is_complex2) {
01346 *preal = 0;
01347
01348 if (z1 < z3 || (z1 == z3 && z2 <= z4)) {
01349 x1 = z1;
01350 x2 = z2;
01351 x3 = z3;
01352 x4 = z4;
01353 } else {
01354 x1 = z3;
01355 x2 = z4;
01356 x3 = z1;
01357 x4 = z2;
01358 }
01359 } else {
01360 *preal = 4;
01361
01362 if (z3 >= z2) {
01363 x1 = z1;
01364 x2 = z2;
01365 x3 = z3;
01366 x4 = z4;
01367 } else if (z4 <= z1) {
01368 x1 = z3;
01369 x2 = z4;
01370 x3 = z1;
01371 x4 = z2;
01372 } else if (z2 > z4) {
01373 x1 = z3;
01374 x2 = z1;
01375 x3 = z4;
01376 x4 = z2;
01377 } else {
01378 x1 = z1;
01379 x2 = z3;
01380 x3 = z2;
01381 x4 = z4;
01382 }
01383 }
01384 }
01385
01386 *px1 = x1;
01387 *px2 = x2;
01388 *px3 = x3;
01389 *px4 = x4;
01390
01391 return CPL_ERROR_NONE;
01392 }
01393
01394 #ifdef IPRLIB_POLYNOMIAL_USE_MONOMIAL_ROOT
01395
01403
01404 static double irplib_polynomial_depress_1d(cpl_polynomial * self)
01405 {
01406
01407 const cpl_size degree = cpl_polynomial_get_degree(self);
01408 const cpl_size nc1 = degree - 1;
01409 const double an = cpl_polynomial_get_coeff(self, °ree);
01410 const double an1 = cpl_polynomial_get_coeff(self, &nc1);
01411 double rmean;
01412 cpl_size i;
01413
01414
01415 cpl_ensure(degree > 0, CPL_ERROR_DATA_NOT_FOUND, 0.0);
01416
01417 assert( an != 0.0 );
01418
01419 rmean = -an1/(an * (double)degree);
01420
01421 if (rmean != 0.0) {
01422
01423 cpl_polynomial_shift_1d(self, 0, rmean);
01424
01425 cpl_polynomial_set_coeff(self, &nc1, 0.0);
01426
01427 }
01428
01429
01430 for (i = 0; i < degree-1; i++) {
01431 const double ai = cpl_polynomial_get_coeff(self, &i) / an;
01432 cpl_polynomial_set_coeff(self, &i, ai);
01433 }
01434
01435 cpl_polynomial_set_coeff(self, °ree, 1.0);
01436
01437 return rmean;
01438 }
01439 #endif
01440
01441
01456
01457 static
01458 cpl_error_code irplib_polynomial_divide_1d_root(cpl_polynomial * p, double r,
01459 double * pres)
01460 {
01461
01462 const cpl_size n = cpl_polynomial_get_degree(p);
01463 double sum;
01464 cpl_size i;
01465
01466
01467 cpl_ensure_code(p != NULL, CPL_ERROR_NULL_INPUT);
01468 cpl_ensure_code(cpl_polynomial_get_dimension(p) == 1,
01469 CPL_ERROR_INVALID_TYPE);
01470 cpl_ensure_code(n > 0, CPL_ERROR_DATA_NOT_FOUND);
01471
01472 sum = cpl_polynomial_get_coeff(p, &n);
01473 cpl_polynomial_set_coeff(p, &n, 0.0);
01474
01475 for (i = n-1; i >= 0; i--) {
01476 const double coeff = cpl_polynomial_get_coeff(p, &i);
01477
01478 cpl_polynomial_set_coeff(p, &i, sum);
01479
01480 sum = coeff + r * sum;
01481
01482 }
01483
01484 if (pres != NULL) *pres = sum;
01485
01486 return CPL_ERROR_NONE;
01487 }