summaryrefslogtreecommitdiff
path: root/libm/double/polyn.c
diff options
context:
space:
mode:
Diffstat (limited to 'libm/double/polyn.c')
-rw-r--r--libm/double/polyn.c471
1 files changed, 471 insertions, 0 deletions
diff --git a/libm/double/polyn.c b/libm/double/polyn.c
new file mode 100644
index 000000000..2927e77f0
--- /dev/null
+++ b/libm/double/polyn.c
@@ -0,0 +1,471 @@
+/* polyn.c
+ * polyr.c
+ * Arithmetic operations on polynomials
+ *
+ * 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 .
+ *
+ *
+ *
+ * sum = poleva( a, na, x ); 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>
+#if ANSIPROT
+void exit (int);
+extern void * malloc ( long );
+extern void free ( void * );
+void polclr ( double *, int );
+void polmov ( double *, int, double * );
+void polmul ( double *, int, double *, int, double * );
+int poldiv ( double *, int, double *, int, double * );
+#else
+void exit();
+void * malloc();
+void free ();
+void polclr(), polmov(), poldiv(), polmul();
+#endif
+#ifndef NULL
+#define NULL 0
+#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 double *pt1 = 0;
+static double *pt2 = 0;
+static double *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(double);
+
+/* Release previously allocated memory, if any. */
+if( pt3 )
+ free(pt3);
+if( pt2 )
+ free(pt2);
+if( pt1 )
+ free(pt1);
+
+/* Allocate new arrays */
+pt1 = (double * )malloc(psize); /* used by polsbt */
+pt2 = (double * )malloc(psize); /* used by polsbt */
+pt3 = (double * )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 )
+double 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] );
+ }
+printf( "\n" );
+}
+
+
+
+/* Set a = 0.
+ */
+void polclr( a, n )
+register double *a;
+int n;
+{
+int i;
+
+if( n > MAXPOL )
+ n = MAXPOL;
+for( i=0; i<=n; i++ )
+ *a++ = 0.0;
+}
+
+
+
+/* Set b = a.
+ */
+void polmov( a, na, b )
+register double *a, *b;
+int na;
+{
+int i;
+
+if( na > MAXPOL )
+ na = MAXPOL;
+
+for( i=0; i<= na; i++ )
+ {
+ *b++ = *a++;
+ }
+}
+
+
+/* c = b * a.
+ */
+void polmul( a, na, b, nb, c )
+double a[], b[], c[];
+int na, nb;
+{
+int i, j, k, nc;
+double x;
+
+nc = na + nb;
+polclr( pt3, MAXPOL );
+
+for( i=0; i<=na; i++ )
+ {
+ x = a[i];
+ for( j=0; j<=nb; j++ )
+ {
+ k = i + j;
+ if( k > MAXPOL )
+ break;
+ pt3[k] += x * b[j];
+ }
+ }
+
+if( nc > MAXPOL )
+ nc = MAXPOL;
+for( i=0; i<=nc; i++ )
+ c[i] = pt3[i];
+}
+
+
+
+
+/* c = b + a.
+ */
+void poladd( a, na, b, nb, c )
+double 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] = b[i];
+ else if( i > nb )
+ c[i] = a[i];
+ else
+ c[i] = b[i] + a[i];
+ }
+}
+
+/* c = b - a.
+ */
+void polsub( a, na, b, nb, c )
+double 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] = b[i];
+ else if( i > nb )
+ c[i] = -a[i];
+ else
+ c[i] = b[i] - a[i];
+ }
+}
+
+
+
+/* c = b/a
+ */
+int poldiv( a, na, b, nb, c )
+double a[], b[], c[];
+int na, nb;
+{
+double quot;
+double *ta, *tb, *tq;
+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 = (double * )malloc( psize );
+polclr( ta, MAXPOL );
+polmov( a, na, ta );
+
+tb = (double * )malloc( psize );
+polclr( tb, MAXPOL );
+polmov( b, nb, tb );
+
+tq = (double * )malloc( psize );
+polclr( tq, MAXPOL );
+
+/* What to do if leading (constant) coefficient
+ * of denominator is zero.
+ */
+if( a[0] == 0.0 )
+ {
+ for( i=0; i<=na; i++ )
+ {
+ if( ta[i] != 0.0 )
+ goto nzero;
+ }
+ mtherr( "poldiv", SING );
+ goto done;
+
+nzero:
+/* Reduce the degree of the denominator. */
+ for( i=0; i<na; i++ )
+ ta[i] = ta[i+1];
+ ta[na] = 0.0;
+
+ if( b[0] != 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] = tb[i+1];
+ tb[nb] = 0.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++ )
+ {
+ quot = tb[i]/ta[0];
+ for( j=0; j<=MAXPOL; j++ )
+ {
+ k = j + i;
+ if( k > MAXPOL )
+ break;
+ tb[k] -= quot * ta[j];
+ }
+ tq[i] = quot;
+ }
+/* 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 )
+double a[], b[], c[];
+int na, nb;
+{
+int i, j, k, n2;
+double x;
+
+/* 0th degree term:
+ */
+polclr( pt1, MAXPOL );
+pt1[0] = b[0];
+
+polclr( pt2, MAXPOL );
+pt2[0] = 1.0;
+n2 = 0;
+
+for( i=1; i<=nb; i++ )
+ {
+/* Form ith power of a. */
+ polmul( a, na, pt2, n2, pt2 );
+ n2 += na;
+ x = b[i];
+/* Add the ith coefficient of b times the ith power of a. */
+ for( j=0; j<=n2; j++ )
+ {
+ if( j > MAXPOL )
+ break;
+ pt1[j] += x * pt2[j];
+ }
+ }
+
+k = n2 + nb;
+if( k > MAXPOL )
+ k = MAXPOL;
+for( i=0; i<=k; i++ )
+ c[i] = pt1[i];
+}
+
+
+
+
+/* Evaluate polynomial a(t) at t = x.
+ */
+double poleva( a, na, x )
+double a[];
+int na;
+double x;
+{
+double s;
+int i;
+
+s = a[na];
+for( i=na-1; i>=0; i-- )
+ {
+ s = s * x + a[i];
+ }
+return(s);
+}
+