2 /* Arithmetic operations on polynomials with rational coefficients
4 * In the following descriptions a, b, c are polynomials of degree
5 * na, nb, nc respectively. The degree of a polynomial cannot
6 * exceed a run-time value MAXPOL. An operation that attempts
7 * to use or generate a polynomial of higher degree may produce a
8 * result that suffers truncation at degree MAXPOL. The value of
9 * MAXPOL is set by calling the function
13 * where maxpol is the desired maximum degree. This must be
14 * done prior to calling any of the other functions in this module.
15 * Memory for internal temporary polynomial storage is allocated
18 * Each polynomial is represented by an array containing its
19 * coefficients, together with a separately declared integer equal
20 * to the degree of the polynomial. The coefficients appear in
21 * ascending order; that is,
24 * a(x) = a[0] + a[1] * x + a[2] * x + ... + a[na] * x .
28 * `a', `b', `c' are arrays of fracts.
29 * poleva( a, na, &x, &sum ); Evaluate polynomial a(t) at t = x.
30 * polprt( a, na, D ); Print the coefficients of a to D digits.
31 * polclr( a, na ); Set a identically equal to zero, up to a[na].
32 * polmov( a, na, b ); Set b = a.
33 * poladd( a, na, b, nb, c ); c = b + a, nc = max(na,nb)
34 * polsub( a, na, b, nb, c ); c = b - a, nc = max(na,nb)
35 * polmul( a, na, b, nb, c ); c = b * a, nc = na+nb
40 * i = poldiv( a, na, b, nb, c ); c = b / a, nc = MAXPOL
42 * returns i = the degree of the first nonzero coefficient of a.
43 * The computed quotient c must be divided by x^i. An error message
44 * is printed if a is identically zero.
47 * Change of variables:
48 * If a and b are polynomials, and t = a(x), then
50 * is a polynomial found by substituting a(x) for t. The
51 * subroutine call for this is
53 * polsbt( a, na, b, nb, c );
57 * poldiv() is an integer routine; poleva() is double.
58 * Any of the arguments a, b, c may refer to the same array.
73 extern void radd ( fract *, fract *, fract * );
74 extern void rsub ( fract *, fract *, fract * );
75 extern void rmul ( fract *, fract *, fract * );
76 extern void rdiv ( fract *, fract *, fract * );
77 void polmov ( fract *, int, fract * );
78 void polmul ( fract *, int, fract *, int, fract * );
79 int poldiv ( fract *, int, fract *, int, fract * );
80 void * malloc ( long );
83 void radd(), rsub(), rmul(), rdiv();
84 void polmov(), polmul();
90 /* near pointer version of malloc() */
92 #define malloc _nmalloc
95 /* Pointers to internal arrays. Note poldiv() allocates
96 * and deallocates some temporary arrays every time it is called.
98 static fract *pt1 = 0;
99 static fract *pt2 = 0;
100 static fract *pt3 = 0;
102 /* Maximum degree of polynomial. */
106 /* Number of bytes (chars) in maximum size polynomial. */
107 static int psize = 0;
110 /* Initialize max degree of polynomials
111 * and allocate temporary storage.
113 void polini( maxdeg )
118 psize = (maxdeg + 1) * sizeof(fract);
120 /* Release previously allocated memory, if any. */
128 /* Allocate new arrays */
129 pt1 = (fract * )malloc(psize); /* used by polsbt */
130 pt2 = (fract * )malloc(psize); /* used by polsbt */
131 pt3 = (fract * )malloc(psize); /* used by polmul */
133 /* Report if failure */
134 if( (pt1 == NULL) || (pt2 == NULL) || (pt3 == NULL) )
136 mtherr( "polini", ERANGE );
143 /* Print the coefficients of a, with d decimal precision.
145 static char *form = "abcdefghijk";
147 void polprt( a, na, d )
154 /* Create format descriptor string for the printout.
155 * Do this partly by hand, since sprintf() may be too
156 * bug-ridden to accomplish this feat by itself.
161 sprintf( p, "%d ", d1 );
166 sprintf( p, "%d ", d );
175 /* Now do the printing.
179 for( i=0; i<=na; i++ )
181 /* Detect end of available line */
188 printf( form, a[i].n );
195 printf( form, a[i].d );
212 for( i=0; i<=n; i++ )
223 void polmov( a, na, b )
232 for( i=0; i<= na; i++ )
242 void polmul( a, na, b, nb, c )
251 polclr( pt3, MAXPOL );
254 for( i=0; i<=na; i++ )
256 for( j=0; j<=nb; j++ )
261 rmul( p, &b[j], &temp ); /*pt3[k] += a[i] * b[j];*/
262 radd( &temp, &pt3[k], &pt3[k] );
269 for( i=0; i<=nc; i++ )
281 void poladd( a, na, b, nb, c )
296 for( i=0; i<=n; i++ )
310 radd( &a[i], &b[i], &c[i] ); /*c[i] = b[i] + a[i];*/
317 void polsub( a, na, b, nb, c )
332 for( i=0; i<=n; i++ )
346 rsub( &a[i], &b[i], &c[i] ); /*c[i] = b[i] - a[i];*/
355 int poldiv( a, na, b, nb, c )
366 /* Allocate temporary arrays. This would be quicker
367 * if done automatically on the stack, but stack space
368 * may be hard to obtain on a small computer.
370 ta = (fract * )malloc( psize );
371 polclr( ta, MAXPOL );
374 tb = (fract * )malloc( psize );
375 polclr( tb, MAXPOL );
378 tq = (fract * )malloc( psize );
379 polclr( tq, MAXPOL );
381 /* What to do if leading (constant) coefficient
382 * of denominator is zero.
386 for( i=0; i<=na; i++ )
391 mtherr( "poldiv", SING );
395 /* Reduce the degree of the denominator. */
396 for( i=0; i<na; i++ )
407 printf( "poldiv singularity, divide quotient by x\n" );
413 /* Reduce degree of numerator. */
414 for( i=0; i<nb; i++ )
422 /* Call self, using reduced polynomials. */
423 sing += poldiv( ta, na, tb, nb, c );
427 /* Long division algorithm. ta[0] is nonzero.
429 for( i=0; i<=MAXPOL; i++ )
431 rdiv( &ta[0], &tb[i], " ); /*quot = tb[i]/ta[0];*/
432 for( j=0; j<=MAXPOL; j++ )
438 rmul( &ta[j], ", &temp ); /*tb[k] -= quot * ta[j];*/
439 rsub( &temp, &tb[k], &tb[k] );
444 /* Send quotient to output array. */
445 polmov( tq, MAXPOL, c );
449 /* Restore allocated memory. */
459 /* Change of variables
460 * Substitute a(y) for the variable x in b(x).
462 * c(x) = b(x) = b(a(y)).
465 void polsbt( a, na, b, nb, c )
475 polclr( pt1, MAXPOL );
479 polclr( pt2, MAXPOL );
485 for( i=1; i<=nb; i++ )
487 /* Form ith power of a. */
488 polmul( a, na, pt2, n2, pt2 );
490 /* Add the ith coefficient of b times the ith power of a. */
491 for( j=0; j<=n2; j++ )
495 rmul( &pt2[j], p, &temp ); /*pt1[j] += b[i] * pt2[j];*/
496 radd( &temp, &pt1[j], &pt1[j] );
504 for( i=0; i<=k; i++ )
514 /* Evaluate polynomial a(t) at t = x.
516 void poleva( a, na, x, s )
527 for( i=na-1; i>=0; i-- )
529 rmul( s, x, &temp ); /*s = s * x + a[i];*/
530 radd( &a[i], &temp, s );