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