123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- /* Arithmetic operations on polynomials with rational coefficients
- *
- * In the following descriptions a, b, c are polynomials of degree
- * na, nb, nc respectively. The degree of a polynomial cannot
- * exceed a run-time value MAXPOL. An operation that attempts
- * to use or generate a polynomial of higher degree may produce a
- * result that suffers truncation at degree MAXPOL. The value of
- * MAXPOL is set by calling the function
- *
- * polini( maxpol );
- *
- * where maxpol is the desired maximum degree. This must be
- * done prior to calling any of the other functions in this module.
- * Memory for internal temporary polynomial storage is allocated
- * by polini().
- *
- * Each polynomial is represented by an array containing its
- * coefficients, together with a separately declared integer equal
- * to the degree of the polynomial. The coefficients appear in
- * ascending order; that is,
- *
- * 2 na
- * a(x) = a[0] + a[1] * x + a[2] * x + ... + a[na] * x .
- *
- *
- *
- * `a', `b', `c' are arrays of fracts.
- * poleva( a, na, &x, &sum ); Evaluate polynomial a(t) at t = x.
- * polprt( a, na, D ); Print the coefficients of a to D digits.
- * polclr( a, na ); Set a identically equal to zero, up to a[na].
- * polmov( a, na, b ); Set b = a.
- * poladd( a, na, b, nb, c ); c = b + a, nc = max(na,nb)
- * polsub( a, na, b, nb, c ); c = b - a, nc = max(na,nb)
- * polmul( a, na, b, nb, c ); c = b * a, nc = na+nb
- *
- *
- * Division:
- *
- * i = poldiv( a, na, b, nb, c ); c = b / a, nc = MAXPOL
- *
- * returns i = the degree of the first nonzero coefficient of a.
- * The computed quotient c must be divided by x^i. An error message
- * is printed if a is identically zero.
- *
- *
- * Change of variables:
- * If a and b are polynomials, and t = a(x), then
- * c(t) = b(a(x))
- * is a polynomial found by substituting a(x) for t. The
- * subroutine call for this is
- *
- * polsbt( a, na, b, nb, c );
- *
- *
- * Notes:
- * poldiv() is an integer routine; poleva() is double.
- * Any of the arguments a, b, c may refer to the same array.
- *
- */
- #include <stdio.h>
- #include <math.h>
- #ifndef NULL
- #define NULL 0
- #endif
- typedef struct{
- double n;
- double d;
- }fract;
- #ifdef ANSIPROT
- extern void radd ( fract *, fract *, fract * );
- extern void rsub ( fract *, fract *, fract * );
- extern void rmul ( fract *, fract *, fract * );
- extern void rdiv ( fract *, fract *, fract * );
- void polmov ( fract *, int, fract * );
- void polmul ( fract *, int, fract *, int, fract * );
- int poldiv ( fract *, int, fract *, int, fract * );
- void * malloc ( long );
- void free ( void * );
- #else
- void radd(), rsub(), rmul(), rdiv();
- void polmov(), polmul();
- int poldiv();
- void * malloc();
- void free ();
- #endif
- /* near pointer version of malloc() */
- /*
- #define malloc _nmalloc
- #define free _nfree
- */
- /* Pointers to internal arrays. Note poldiv() allocates
- * and deallocates some temporary arrays every time it is called.
- */
- static fract *pt1 = 0;
- static fract *pt2 = 0;
- static fract *pt3 = 0;
- /* Maximum degree of polynomial. */
- int MAXPOL = 0;
- extern int MAXPOL;
- /* Number of bytes (chars) in maximum size polynomial. */
- static int psize = 0;
- /* Initialize max degree of polynomials
- * and allocate temporary storage.
- */
- void polini( maxdeg )
- int maxdeg;
- {
- MAXPOL = maxdeg;
- psize = (maxdeg + 1) * sizeof(fract);
- /* Release previously allocated memory, if any. */
- if( pt3 )
- free(pt3);
- if( pt2 )
- free(pt2);
- if( pt1 )
- free(pt1);
- /* Allocate new arrays */
- pt1 = (fract * )malloc(psize); /* used by polsbt */
- pt2 = (fract * )malloc(psize); /* used by polsbt */
- pt3 = (fract * )malloc(psize); /* used by polmul */
- /* Report if failure */
- if( (pt1 == NULL) || (pt2 == NULL) || (pt3 == NULL) )
- {
- mtherr( "polini", ERANGE );
- exit(1);
- }
- }
- /* Print the coefficients of a, with d decimal precision.
- */
- static char *form = "abcdefghijk";
- void polprt( a, na, d )
- fract a[];
- int na, d;
- {
- int i, j, d1;
- char *p;
- /* Create format descriptor string for the printout.
- * Do this partly by hand, since sprintf() may be too
- * bug-ridden to accomplish this feat by itself.
- */
- p = form;
- *p++ = '%';
- d1 = d + 8;
- sprintf( p, "%d ", d1 );
- p += 1;
- if( d1 >= 10 )
- p += 1;
- *p++ = '.';
- sprintf( p, "%d ", d );
- p += 1;
- if( d >= 10 )
- p += 1;
- *p++ = 'e';
- *p++ = ' ';
- *p++ = '\0';
- /* Now do the printing.
- */
- d1 += 1;
- j = 0;
- for( i=0; i<=na; i++ )
- {
- /* Detect end of available line */
- j += d1;
- if( j >= 78 )
- {
- printf( "\n" );
- j = d1;
- }
- printf( form, a[i].n );
- j += d1;
- if( j >= 78 )
- {
- printf( "\n" );
- j = d1;
- }
- printf( form, a[i].d );
- }
- printf( "\n" );
- }
- /* Set a = 0.
- */
- void polclr( a, n )
- fract a[];
- int n;
- {
- int i;
- if( n > MAXPOL )
- n = MAXPOL;
- for( i=0; i<=n; i++ )
- {
- a[i].n = 0.0;
- a[i].d = 1.0;
- }
- }
- /* Set b = a.
- */
- void polmov( a, na, b )
- fract a[], b[];
- int na;
- {
- int i;
- if( na > MAXPOL )
- na = MAXPOL;
- for( i=0; i<= na; i++ )
- {
- b[i].n = a[i].n;
- b[i].d = a[i].d;
- }
- }
- /* c = b * a.
- */
- void polmul( a, na, b, nb, c )
- fract a[], b[], c[];
- int na, nb;
- {
- int i, j, k, nc;
- fract temp;
- fract *p;
- nc = na + nb;
- polclr( pt3, MAXPOL );
- p = &a[0];
- for( i=0; i<=na; i++ )
- {
- for( j=0; j<=nb; j++ )
- {
- k = i + j;
- if( k > MAXPOL )
- break;
- rmul( p, &b[j], &temp ); /*pt3[k] += a[i] * b[j];*/
- radd( &temp, &pt3[k], &pt3[k] );
- }
- ++p;
- }
- if( nc > MAXPOL )
- nc = MAXPOL;
- for( i=0; i<=nc; i++ )
- {
- c[i].n = pt3[i].n;
- c[i].d = pt3[i].d;
- }
- }
-
- /* c = b + a.
- */
- void poladd( a, na, b, nb, c )
- fract a[], b[], c[];
- int na, nb;
- {
- int i, n;
- if( na > nb )
- n = na;
- else
- n = nb;
- if( n > MAXPOL )
- n = MAXPOL;
- for( i=0; i<=n; i++ )
- {
- if( i > na )
- {
- c[i].n = b[i].n;
- c[i].d = b[i].d;
- }
- else if( i > nb )
- {
- c[i].n = a[i].n;
- c[i].d = a[i].d;
- }
- else
- {
- radd( &a[i], &b[i], &c[i] ); /*c[i] = b[i] + a[i];*/
- }
- }
- }
- /* c = b - a.
- */
- void polsub( a, na, b, nb, c )
- fract a[], b[], c[];
- int na, nb;
- {
- int i, n;
- if( na > nb )
- n = na;
- else
- n = nb;
- if( n > MAXPOL )
- n = MAXPOL;
- for( i=0; i<=n; i++ )
- {
- if( i > na )
- {
- c[i].n = b[i].n;
- c[i].d = b[i].d;
- }
- else if( i > nb )
- {
- c[i].n = -a[i].n;
- c[i].d = a[i].d;
- }
- else
- {
- rsub( &a[i], &b[i], &c[i] ); /*c[i] = b[i] - a[i];*/
- }
- }
- }
- /* c = b/a
- */
- int poldiv( a, na, b, nb, c )
- fract a[], b[], c[];
- int na, nb;
- {
- fract *ta, *tb, *tq;
- fract quot;
- fract temp;
- int i, j, k, sing;
- sing = 0;
- /* Allocate temporary arrays. This would be quicker
- * if done automatically on the stack, but stack space
- * may be hard to obtain on a small computer.
- */
- ta = (fract * )malloc( psize );
- polclr( ta, MAXPOL );
- polmov( a, na, ta );
- tb = (fract * )malloc( psize );
- polclr( tb, MAXPOL );
- polmov( b, nb, tb );
- tq = (fract * )malloc( psize );
- polclr( tq, MAXPOL );
- /* What to do if leading (constant) coefficient
- * of denominator is zero.
- */
- if( a[0].n == 0.0 )
- {
- for( i=0; i<=na; i++ )
- {
- if( ta[i].n != 0.0 )
- goto nzero;
- }
- mtherr( "poldiv", SING );
- goto done;
- nzero:
- /* Reduce the degree of the denominator. */
- for( i=0; i<na; i++ )
- {
- ta[i].n = ta[i+1].n;
- ta[i].d = ta[i+1].d;
- }
- ta[na].n = 0.0;
- ta[na].d = 1.0;
- if( b[0].n != 0.0 )
- {
- /* Optional message:
- printf( "poldiv singularity, divide quotient by x\n" );
- */
- sing += 1;
- }
- else
- {
- /* Reduce degree of numerator. */
- for( i=0; i<nb; i++ )
- {
- tb[i].n = tb[i+1].n;
- tb[i].d = tb[i+1].d;
- }
- tb[nb].n = 0.0;
- tb[nb].d = 1.0;
- }
- /* Call self, using reduced polynomials. */
- sing += poldiv( ta, na, tb, nb, c );
- goto done;
- }
- /* Long division algorithm. ta[0] is nonzero.
- */
- for( i=0; i<=MAXPOL; i++ )
- {
- rdiv( &ta[0], &tb[i], " ); /*quot = tb[i]/ta[0];*/
- for( j=0; j<=MAXPOL; j++ )
- {
- k = j + i;
- if( k > MAXPOL )
- break;
- rmul( &ta[j], ", &temp ); /*tb[k] -= quot * ta[j];*/
- rsub( &temp, &tb[k], &tb[k] );
- }
- tq[i].n = quot.n;
- tq[i].d = quot.d;
- }
- /* Send quotient to output array. */
- polmov( tq, MAXPOL, c );
- done:
- /* Restore allocated memory. */
- free(tq);
- free(tb);
- free(ta);
- return( sing );
- }
- /* Change of variables
- * Substitute a(y) for the variable x in b(x).
- * x = a(y)
- * c(x) = b(x) = b(a(y)).
- */
- void polsbt( a, na, b, nb, c )
- fract a[], b[], c[];
- int na, nb;
- {
- int i, j, k, n2;
- fract temp;
- fract *p;
- /* 0th degree term:
- */
- polclr( pt1, MAXPOL );
- pt1[0].n = b[0].n;
- pt1[0].d = b[0].d;
- polclr( pt2, MAXPOL );
- pt2[0].n = 1.0;
- pt2[0].d = 1.0;
- n2 = 0;
- p = &b[1];
- for( i=1; i<=nb; i++ )
- {
- /* Form ith power of a. */
- polmul( a, na, pt2, n2, pt2 );
- n2 += na;
- /* Add the ith coefficient of b times the ith power of a. */
- for( j=0; j<=n2; j++ )
- {
- if( j > MAXPOL )
- break;
- rmul( &pt2[j], p, &temp ); /*pt1[j] += b[i] * pt2[j];*/
- radd( &temp, &pt1[j], &pt1[j] );
- }
- ++p;
- }
- k = n2 + nb;
- if( k > MAXPOL )
- k = MAXPOL;
- for( i=0; i<=k; i++ )
- {
- c[i].n = pt1[i].n;
- c[i].d = pt1[i].d;
- }
- }
- /* Evaluate polynomial a(t) at t = x.
- */
- void poleva( a, na, x, s )
- fract a[];
- int na;
- fract *x;
- fract *s;
- {
- int i;
- fract temp;
- s->n = a[na].n;
- s->d = a[na].d;
- for( i=na-1; i>=0; i-- )
- {
- rmul( s, x, &temp ); /*s = s * x + a[i];*/
- radd( &a[i], &temp, s );
- }
- }
|