poly.c

Go to the documentation of this file.
00001 /*                          P O L Y . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup poly */
00023 /*@{*/
00024 /** @file poly.c
00025  *      Library for dealing with polynomials.
00026  *
00027  *  Author -
00028  *      Jeff Hanes
00029  *
00030  *  Source -
00031  *      The U. S. Army Research Laboratory
00032  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
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  *      bn_poly_mul 
00065  *
00066  * @brief multiply two polynomials
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         /* Not one of the common (or easy) cases. */
00094         {
00095                 register int            ct1, ct2;
00096 
00097                 *product = bn_Zero_poly;
00098 
00099                 /* If the degree of the product will be larger than the
00100                  * maximum size allowed in "polyno.h", then return a null
00101                  * pointer to indicate failure.
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  *      bn_poly_scale 
00119  * @brief
00120  * scale a polynomial
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  *      bn_poly_add 
00136  * @brief
00137  * add two polynomials
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  *      bn_poly_sub 
00170  * @brief
00171  * subtract two polynomials
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 /**     s y n D i v ( )
00205  * @brief
00206  *      Divides any polynomial into any other polynomial using synthetic
00207  *      division.  Both polynomials must have real coefficients.
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 /**     q u a d r a t i c ( )
00237  *@brief
00238  *      Uses the quadratic formula to find the roots (in `complex' form)
00239  *      of any quadratic equation with real coefficients.
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                 /* root = -cf[2] / cf[1] */
00248                 if( NEAR_ZERO( quadrat->cf[1], SQRT_SMALL_FASTF ) )  {
00249                         /* No solution.  Now what? */
00250                         bu_log("bn_poly_quadratic_roots(): ERROR, no solution\n");
00251                         return -1;
00252                 }
00253                 /* Fake it as a repeated root. */
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;       /* OK - repeated root */
00257         }
00258         /* What to do if cf[1] > SQRT_MAX_FASTF ? */
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;               /* OK */
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 /**     c u b i c ( )
00281  *@brief
00282  *      Uses the cubic formula to find the roots ( in `complex' form )
00283  *      of any cubic equation with real coefficients.
00284  *
00285  *      to solve a polynomial of the form:
00286  *
00287  *              X**3 + c1*X**2 + c2*X + c3 = 0,
00288  *
00289  *      first reduce it to the form:
00290  *
00291  *              Y**3 + a*Y + b = 0,
00292  *
00293  *      where
00294  *              Y = X + c1/3,
00295  *      and
00296  *              a = c2 - c1**2/3,
00297  *              b = ( 2*c1**3 - 9*c1*c2 + 27*c3 )/27.
00298  *
00299  *      Then we define the value delta,   D = b**2/4 + a**3/27.
00300  *
00301  *      If D > 0, there will be one real root and two conjugate
00302  *      complex roots.
00303  *      If D = 0, there will be three real roots at least two of
00304  *      which are equal.
00305  *      If D < 0, there will be three unequal real roots.
00306  *
00307  *      Returns 1 for success, 0 for fail.
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);     /* Renew handler */
00317         longjmp(bn_abort_buf, 1);       /* return error code */
00318 }
00319 
00320 /*
00321  *                      B N _ P O L Y _ C U B I C _ R O O T S
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                 /* bn_abort_buf is NOT parallel! */
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);      /* FAIL */
00341                 }
00342         }
00343 
00344         c1 = eqn->cf[1];
00345         if( Abs(c1) > SQRT_MAX_FASTF )  return(0);      /* FAIL */
00346 
00347         c1_3rd = c1 * THIRD;
00348         a = eqn->cf[2] - c1*c1_3rd;
00349         if( Abs(a) > SQRT_MAX_FASTF )  return(0);       /* FAIL */
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);       /* FAIL */
00352 
00353         if( (delta = a*a) > SQRT_MAX_FASTF ) return(0); /* FAIL */
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;           /* cos( phi ); */
00386                         sn_phi_s3 = 0.0;        /* sin( phi ) * SQRT3; */
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;           /* cos( phi ); */
00394                                 sn_phi_s3 = 0.0;        /* sin( phi ) * SQRT3; */
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);              /* OK */
00418 }
00419 
00420 
00421 /**
00422  *                      B N _ P O L Y _ Q U A R T I C _ R O O T S
00423  *@brief
00424  *      Uses the quartic formula to find the roots ( in `complex' form )
00425  *      of any quartic equation with real coefficients.
00426  *
00427  *      @return 1 for success
00428  *      @return 0 for fail.
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 );            /* FAIL */
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);      /* FAIL */
00462                 }
00463                 p = 0;
00464         } else {
00465                 p = sqrt( p );
00466         }
00467         if( q < 0 )  {
00468                 if( q < -1.0e-8 )  {
00469                         return(0);      /* FAIL */
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);      /* FAIL */
00496                 }
00497         }
00498 
00499         bn_poly_quadratic_roots( &roots[0], &quad1 );
00500         bn_poly_quadratic_roots( &roots[2], &quad2 );
00501         return(1);              /* SUCCESS */
00502 }
00503 
00504 
00505 /**
00506  *                      B N _ P R _ P O L Y
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                         /* For constant term, add nothing */
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  *                      B N _ P R _ R O O T S
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  * Local Variables:
00564  * mode: C
00565  * tab-width: 8
00566  * c-basic-offset: 4
00567  * indent-tabs-mode: t
00568  * End:
00569  * ex: shiftwidth=4 tabstop=8
00570  */

Generated on Mon Sep 18 01:24:47 2006 for BRL-CAD by  doxygen 1.4.6