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
00033
00034
00035
00036
00037 #ifndef lint
00038 static const char RCSpoly[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbn/poly.c,v 14.10 2006/09/04 04:42:40 lbutler Exp $ (ARL)";
00039 #endif
00040
00041 #include "common.h"
00042
00043
00044
00045 #include <stdio.h>
00046 #include <math.h>
00047 #include <signal.h>
00048 #include "machine.h"
00049 #include "bu.h"
00050 #include "vmath.h"
00051 #include "bn.h"
00052
00053 #define Abs( a ) ((a) >= 0 ? (a) : -(a))
00054 #define Max( a, b ) ((a) > (b) ? (a) : (b))
00055
00056 #ifndef M_PI
00057 #define M_PI 3.14159265358979323846
00058 #endif
00059 #define PI_DIV_3 (M_PI/3.0)
00060
00061 static const struct bn_poly bn_Zero_poly = { BN_POLY_MAGIC, 0, {0.0} };
00062
00063
00064
00065
00066
00067
00068 struct bn_poly *
00069 bn_poly_mul(register struct bn_poly *product, register const struct bn_poly *m1, register const struct bn_poly *m2)
00070 {
00071 if( m1->dgr == 1 && m2->dgr == 1 ) {
00072 product->dgr = 2;
00073 product->cf[0] = m1->cf[0] * m2->cf[0];
00074 product->cf[1] = m1->cf[0] * m2->cf[1] +
00075 m1->cf[1] * m2->cf[0];
00076 product->cf[2] = m1->cf[1] * m2->cf[1];
00077 return(product);
00078 }
00079 if( m1->dgr == 2 && m2->dgr == 2 ) {
00080 product->dgr = 4;
00081 product->cf[0] = m1->cf[0] * m2->cf[0];
00082 product->cf[1] = m1->cf[0] * m2->cf[1] +
00083 m1->cf[1] * m2->cf[0];
00084 product->cf[2] = m1->cf[0] * m2->cf[2] +
00085 m1->cf[1] * m2->cf[1] +
00086 m1->cf[2] * m2->cf[0];
00087 product->cf[3] = m1->cf[1] * m2->cf[2] +
00088 m1->cf[2] * m2->cf[1];
00089 product->cf[4] = m1->cf[2] * m2->cf[2];
00090 return(product);
00091 }
00092
00093
00094 {
00095 register int ct1, ct2;
00096
00097 *product = bn_Zero_poly;
00098
00099
00100
00101
00102
00103 if ( (product->dgr = m1->dgr + m2->dgr) > BN_MAX_POLY_DEGREE )
00104 return BN_POLY_NULL;
00105
00106 for ( ct1=0; ct1 <= m1->dgr; ++ct1 ){
00107 for ( ct2=0; ct2 <= m2->dgr; ++ct2 ){
00108 product->cf[ct1+ct2] +=
00109 m1->cf[ct1] * m2->cf[ct2];
00110 }
00111 }
00112 }
00113 return product;
00114 }
00115
00116
00117
00118
00119
00120
00121
00122 struct bn_poly *
00123 bn_poly_scale(register struct bn_poly *eqn, double factor)
00124 {
00125 register int cnt;
00126
00127 for ( cnt=0; cnt <= eqn->dgr; ++cnt ){
00128 eqn->cf[cnt] *= factor;
00129 }
00130 return eqn;
00131 }
00132
00133
00134
00135
00136
00137
00138
00139 struct bn_poly *
00140 bn_poly_add(register struct bn_poly *sum, register const struct bn_poly *poly1, register const struct bn_poly *poly2)
00141 {
00142 LOCAL struct bn_poly tmp;
00143 register int i, offset;
00144
00145 offset = Abs(poly1->dgr - poly2->dgr);
00146
00147 tmp = bn_Zero_poly;
00148
00149 if ( poly1->dgr >= poly2->dgr ){
00150 *sum = *poly1;
00151 for ( i=0; i <= poly2->dgr; ++i ){
00152 tmp.cf[i+offset] = poly2->cf[i];
00153 }
00154 } else {
00155 *sum = *poly2;
00156 for ( i=0; i <= poly1->dgr; ++i ){
00157 tmp.cf[i+offset] = poly1->cf[i];
00158 }
00159 }
00160
00161 for ( i=0; i <= sum->dgr; ++i ){
00162 sum->cf[i] += tmp.cf[i];
00163 }
00164 return sum;
00165 }
00166
00167
00168
00169
00170
00171
00172
00173 struct bn_poly *
00174 bn_poly_sub(register struct bn_poly *diff, register const struct bn_poly *poly1, register const struct bn_poly *poly2)
00175 {
00176 LOCAL struct bn_poly tmp;
00177 register int i, offset;
00178
00179 offset = Abs(poly1->dgr - poly2->dgr);
00180
00181 *diff = bn_Zero_poly;
00182 tmp = bn_Zero_poly;
00183
00184 if ( poly1->dgr >= poly2->dgr ){
00185 *diff = *poly1;
00186 for ( i=0; i <= poly2->dgr; ++i ){
00187 tmp.cf[i+offset] = poly2->cf[i];
00188 }
00189 } else {
00190 diff->dgr = poly2->dgr;
00191 for ( i=0; i <= poly1->dgr; ++i ){
00192 diff->cf[i+offset] = poly1->cf[i];
00193 }
00194 tmp = *poly2;
00195 }
00196
00197 for ( i=0; i <= diff->dgr; ++i ){
00198 diff->cf[i] -= tmp.cf[i];
00199 }
00200 return diff;
00201 }
00202
00203
00204
00205
00206
00207
00208
00209 void
00210 bn_poly_synthetic_division(register struct bn_poly *quo, register struct bn_poly *rem, register const struct bn_poly *dvdend, register const struct bn_poly *dvsor)
00211 {
00212 register int div;
00213 register int n;
00214
00215 *quo = *dvdend;
00216 *rem = bn_Zero_poly;
00217
00218 if ((quo->dgr = dvdend->dgr - dvsor->dgr) < 0)
00219 quo->dgr = -1;
00220 if ((rem->dgr = dvsor->dgr - 1) > dvdend->dgr)
00221 rem->dgr = dvdend->dgr;
00222
00223 for ( n=0; n <= quo->dgr; ++n){
00224 quo->cf[n] /= dvsor->cf[0];
00225 for ( div=1; div <= dvsor->dgr; ++div){
00226 quo->cf[n+div] -= quo->cf[n] * dvsor->cf[div];
00227 }
00228 }
00229 for ( n=1; n<=(rem->dgr+1); ++n){
00230 rem->cf[n-1] = quo->cf[quo->dgr+n];
00231 quo->cf[quo->dgr+n] = 0;
00232 }
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 int
00242 bn_poly_quadratic_roots(register struct bn_complex *roots, register const struct bn_poly *quadrat)
00243 {
00244 LOCAL fastf_t discrim, denom, rad;
00245
00246 if( NEAR_ZERO( quadrat->cf[0], SQRT_SMALL_FASTF ) ) {
00247
00248 if( NEAR_ZERO( quadrat->cf[1], SQRT_SMALL_FASTF ) ) {
00249
00250 bu_log("bn_poly_quadratic_roots(): ERROR, no solution\n");
00251 return -1;
00252 }
00253
00254 roots[0].re = roots[1].re = -quadrat->cf[2]/quadrat->cf[1];
00255 roots[0].im = roots[1].im = 0.0;
00256 return 1;
00257 }
00258
00259
00260 discrim = quadrat->cf[1]*quadrat->cf[1] - 4.0* quadrat->cf[0]*quadrat->cf[2];
00261 denom = 0.5 / quadrat->cf[0];
00262 if ( discrim >= 0.0 ){
00263 rad = sqrt( discrim );
00264 roots[0].re = ( -quadrat->cf[1] + rad ) * denom;
00265 roots[1].re = ( -quadrat->cf[1] - rad ) * denom;
00266 roots[1].im = roots[0].im = 0.0;
00267 } else {
00268 roots[1].re = roots[0].re = -quadrat->cf[1] * denom;
00269 roots[1].im = -(roots[0].im = sqrt( -discrim ) * denom);
00270 }
00271 return 0;
00272 }
00273
00274
00275 #define SQRT3 1.732050808
00276 #define THIRD 0.333333333333333333333333333
00277 #define INV_TWENTYSEVEN 0.037037037037037037037037037
00278 #define CUBEROOT( a ) (( (a) >= 0.0 ) ? pow( a, THIRD ) : -pow( -(a), THIRD ))
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 static int bn_expecting_fpe = 0;
00310 static jmp_buf bn_abort_buf;
00311 HIDDEN void bn_catch_FPE(int sig)
00312 {
00313 if( !bn_expecting_fpe )
00314 bu_bomb("bn_catch_FPE() unexpected SIGFPE!");
00315 if( !bu_is_parallel() )
00316 (void)signal(SIGFPE, bn_catch_FPE);
00317 longjmp(bn_abort_buf, 1);
00318 }
00319
00320
00321
00322
00323 int
00324 bn_poly_cubic_roots(register struct bn_complex *roots, register const struct bn_poly *eqn)
00325 {
00326 LOCAL fastf_t a, b, c1, c1_3rd, delta;
00327 register int i;
00328 static int first_time = 1;
00329
00330 if( !bu_is_parallel() ) {
00331
00332 if( first_time ) {
00333 first_time = 0;
00334 (void)signal(SIGFPE, bn_catch_FPE);
00335 }
00336 bn_expecting_fpe = 1;
00337 if( setjmp( bn_abort_buf ) ) {
00338 (void)signal(SIGFPE, bn_catch_FPE);
00339 bu_log("bn_poly_cubic_roots() Floating Point Error\n");
00340 return(0);
00341 }
00342 }
00343
00344 c1 = eqn->cf[1];
00345 if( Abs(c1) > SQRT_MAX_FASTF ) return(0);
00346
00347 c1_3rd = c1 * THIRD;
00348 a = eqn->cf[2] - c1*c1_3rd;
00349 if( Abs(a) > SQRT_MAX_FASTF ) return(0);
00350 b = (2.0*c1*c1*c1 - 9.0*c1*eqn->cf[2] + 27.0*eqn->cf[3])*INV_TWENTYSEVEN;
00351 if( Abs(b) > SQRT_MAX_FASTF ) return(0);
00352
00353 if( (delta = a*a) > SQRT_MAX_FASTF ) return(0);
00354 delta = b*b*0.25 + delta*a*INV_TWENTYSEVEN;
00355
00356 if ( delta > 0.0 ){
00357 LOCAL fastf_t r_delta, A, B;
00358
00359 r_delta = sqrt( delta );
00360 A = B = -0.5 * b;
00361 A += r_delta;
00362 B -= r_delta;
00363
00364 A = CUBEROOT( A );
00365 B = CUBEROOT( B );
00366
00367 roots[2].re = roots[1].re = -0.5 * ( roots[0].re = A + B );
00368
00369 roots[0].im = 0.0;
00370 roots[2].im = -( roots[1].im = (A - B)*SQRT3*0.5 );
00371 } else if ( delta == 0.0 ){
00372 LOCAL fastf_t b_2;
00373 b_2 = -0.5 * b;
00374
00375 roots[0].re = 2.0* CUBEROOT( b_2 );
00376 roots[2].re = roots[1].re = -0.5 * roots[0].re;
00377 roots[2].im = roots[1].im = roots[0].im = 0.0;
00378 } else {
00379 LOCAL fastf_t phi, fact;
00380 LOCAL fastf_t cs_phi, sn_phi_s3;
00381
00382 if( a >= 0.0 ) {
00383 fact = 0.0;
00384 phi = 0.0;
00385 cs_phi = 1.0;
00386 sn_phi_s3 = 0.0;
00387 } else {
00388 FAST fastf_t f;
00389 a *= -THIRD;
00390 fact = sqrt( a );
00391 if( (f = b * (-0.5) / (a*fact)) >= 1.0 ) {
00392 phi = 0.0;
00393 cs_phi = 1.0;
00394 sn_phi_s3 = 0.0;
00395 } else if( f <= -1.0 ) {
00396 phi = PI_DIV_3;
00397 cs_phi = cos( phi );
00398 sn_phi_s3 = sin( phi ) * SQRT3;
00399 } else {
00400 phi = acos( f ) * THIRD;
00401 cs_phi = cos( phi );
00402 sn_phi_s3 = sin( phi ) * SQRT3;
00403 }
00404 }
00405
00406 roots[0].re = 2.0*fact*cs_phi;
00407 roots[1].re = fact*( sn_phi_s3 - cs_phi);
00408 roots[2].re = fact*( -sn_phi_s3 - cs_phi);
00409 roots[2].im = roots[1].im = roots[0].im = 0.0;
00410 }
00411 for ( i=0; i < 3; ++i )
00412 roots[i].re -= c1_3rd;
00413
00414 if( !bu_is_parallel() )
00415 bn_expecting_fpe = 0;
00416
00417 return(1);
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 int
00431 bn_poly_quartic_roots(register struct bn_complex *roots, register const struct bn_poly *eqn)
00432 {
00433 LOCAL struct bn_poly cube, quad1, quad2;
00434 LOCAL bn_complex_t u[3];
00435 LOCAL fastf_t U, p, q, q1, q2;
00436 #define Max3(a,b,c) ((c)>((a)>(b)?(a):(b)) ? (c) : ((a)>(b)?(a):(b)))
00437
00438 cube.dgr = 3;
00439 cube.cf[0] = 1.0;
00440 cube.cf[1] = -eqn->cf[2];
00441 cube.cf[2] = eqn->cf[3]*eqn->cf[1]
00442 - 4*eqn->cf[4];
00443 cube.cf[3] = -eqn->cf[3]*eqn->cf[3]
00444 - eqn->cf[4]*eqn->cf[1]*eqn->cf[1]
00445 + 4*eqn->cf[4]*eqn->cf[2];
00446
00447 if( !bn_poly_cubic_roots( u, &cube ) ) {
00448 return( 0 );
00449 }
00450 if ( u[1].im != 0.0 ){
00451 U = u[0].re;
00452 } else {
00453 U = Max3( u[0].re, u[1].re, u[2].re );
00454 }
00455
00456 p = eqn->cf[1]*eqn->cf[1]*0.25 + U - eqn->cf[2];
00457 U *= 0.5;
00458 q = U*U - eqn->cf[4];
00459 if( p < 0 ) {
00460 if( p < -1.0e-8 ) {
00461 return(0);
00462 }
00463 p = 0;
00464 } else {
00465 p = sqrt( p );
00466 }
00467 if( q < 0 ) {
00468 if( q < -1.0e-8 ) {
00469 return(0);
00470 }
00471 q = 0;
00472 } else {
00473 q = sqrt( q );
00474 }
00475
00476 quad1.dgr = quad2.dgr = 2;
00477 quad1.cf[0] = quad2.cf[0] = 1.0;
00478 quad1.cf[1] = eqn->cf[1]*0.5;
00479 quad2.cf[1] = quad1.cf[1] + p;
00480 quad1.cf[1] -= p;
00481
00482 q1 = U - q;
00483 q2 = U + q;
00484
00485 p = quad1.cf[1]*q2 + quad2.cf[1]*q1 - eqn->cf[3];
00486 if( Abs( p ) < 1.0e-8){
00487 quad1.cf[2] = q1;
00488 quad2.cf[2] = q2;
00489 } else {
00490 q = quad1.cf[1]*q1 + quad2.cf[1]*q2 - eqn->cf[3];
00491 if( Abs( q ) < 1.0e-8 ){
00492 quad1.cf[2] = q2;
00493 quad2.cf[2] = q1;
00494 } else {
00495 return(0);
00496 }
00497 }
00498
00499 bn_poly_quadratic_roots( &roots[0], &quad1 );
00500 bn_poly_quadratic_roots( &roots[2], &quad2 );
00501 return(1);
00502 }
00503
00504
00505
00506
00507
00508 void
00509 bn_pr_poly(const char *title, register const struct bn_poly *eqn)
00510 {
00511 register int n;
00512 register int exp;
00513 struct bu_vls str;
00514 char buf[48];
00515
00516 bu_vls_init( &str );
00517 bu_vls_extend( &str, 196 );
00518 bu_vls_strcat( &str, title );
00519 sprintf(buf, " polynomial, degree = %d\n", eqn->dgr);
00520 bu_vls_strcat( &str, buf );
00521
00522 exp = eqn->dgr;
00523 for ( n=0; n<=eqn->dgr; n++,exp-- ) {
00524 register double coeff = eqn->cf[n];
00525 if( n > 0 ) {
00526 if( coeff < 0 ) {
00527 bu_vls_strcat( &str, " - " );
00528 coeff = -coeff;
00529 } else {
00530 bu_vls_strcat( &str, " + " );
00531 }
00532 }
00533 bu_vls_printf( &str, "%g", coeff );
00534 if( exp > 1 ) {
00535 bu_vls_printf( &str, " *X^%d", exp );
00536 } else if( exp == 1 ) {
00537
00538 bu_vls_strcat( &str, " *X" );
00539 } else {
00540
00541 }
00542 }
00543 bu_vls_strcat( &str, "\n" );
00544 bu_log( "%s", bu_vls_addr(&str) );
00545 bu_vls_free( &str );
00546 }
00547
00548
00549
00550
00551 void
00552 bn_pr_roots(const char *title, const struct bn_complex *roots, int n)
00553 {
00554 register int i;
00555
00556 bu_log("%s: %d roots:\n", title, n );
00557 for( i=0; i<n; i++ ) {
00558 bu_log("%4d %e + i * %e\n", i, roots[i].re, roots[i].im );
00559 }
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570