| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 | 
/* Square root, sine, cosine, and arctangent of polynomial. * See polyn.c for data structures and discussion. */#include <stdio.h>#include <math.h>#ifdef ANSIPROTextern double atan2 ( double, double );extern double sqrt ( double );extern double fabs ( double );extern double sin ( double );extern double cos ( double );extern void polclr ( double *a, int n );extern void polmov ( double *a, int na, double *b );extern void polmul ( double a[], int na, double b[], int nb, double c[] );extern void poladd ( double a[], int na, double b[], int nb, double c[] );extern void polsub ( double a[], int na, double b[], int nb, double c[] );extern int poldiv ( double a[], int na, double b[], int nb, double c[] );extern void polsbt ( double a[], int na, double b[], int nb, double c[] );extern void * malloc ( long );extern void free ( void * );#elsedouble atan2(), sqrt(), fabs(), sin(), cos();void polclr(), polmov(), polsbt(), poladd(), polsub(), polmul();int poldiv();void * malloc();void free ();#endif/* Highest degree of polynomial to be handled   by the polyn.c subroutine package.  */#define N 16/* Highest degree actually initialized at runtime.  */extern int MAXPOL;/* Taylor series coefficients for various functions */double patan[N+1] = {  0.0,     1.0,      0.0, -1.0/3.0,     0.0,  1.0/5.0, 0.0, -1.0/7.0,      0.0, 1.0/9.0, 0.0, -1.0/11.0,  0.0, 1.0/13.0, 0.0, -1.0/15.0, 0.0 };double psin[N+1] = {  0.0, 1.0, 0.0,   -1.0/6.0,  0.0, 1.0/120.0,  0.0,  -1.0/5040.0, 0.0, 1.0/362880.0, 0.0, -1.0/39916800.0,  0.0, 1.0/6227020800.0, 0.0, -1.0/1.307674368e12, 0.0};double pcos[N+1] = {  1.0, 0.0,   -1.0/2.0,  0.0, 1.0/24.0,  0.0,  -1.0/720.0, 0.0, 1.0/40320.0, 0.0, -1.0/3628800.0, 0.0,  1.0/479001600.0, 0.0, -1.0/8.7179291e10, 0.0, 1.0/2.0922789888e13};double pasin[N+1] = {  0.0,     1.0,  0.0, 1.0/6.0,  0.0,  3.0/40.0, 0.0, 15.0/336.0, 0.0, 105.0/3456.0, 0.0, 945.0/42240.0,  0.0, 10395.0/599040.0 , 0.0, 135135.0/9676800.0 , 0.0};/* Square root of 1 + x.  */double psqrt[N+1] = {  1.0, 1./2., -1./8., 1./16., -5./128., 7./256., -21./1024., 33./2048.,  -429./32768., 715./65536., -2431./262144., 4199./524288., -29393./4194304.,  52003./8388608., -185725./33554432., 334305./67108864.,  -9694845./2147483648.};/* Arctangent of the ratio num/den of two polynomials. */voidpolatn( num, den, ans, nn )     double num[], den[], ans[];     int nn;{  double a, t;  double *polq, *polu, *polt;  int i;  if (nn > N)    {      mtherr ("polatn", OVERFLOW);      return;    }  /* arctan( a + b ) = arctan(a) + arctan( b/(1 + ab + a**2) ) */  t = num[0];  a = den[0];  if( (t == 0.0) && (a == 0.0 ) )    {      t = num[1];      a = den[1];    }  t = atan2( t, a );  /* arctan(num/den), the ANSI argument order */  polq = (double * )malloc( (MAXPOL+1) * sizeof (double) );  polu = (double * )malloc( (MAXPOL+1) * sizeof (double) );  polt = (double * )malloc( (MAXPOL+1) * sizeof (double) );  polclr( polq, MAXPOL );  i = poldiv( den, nn, num, nn, polq );  a = polq[0]; /* a */  polq[0] = 0.0; /* b */  polmov( polq, nn, polu ); /* b */  /* Form the polynomial     1 + ab + a**2     where a is a scalar.  */  for( i=0; i<=nn; i++ )    polu[i] *= a;  polu[0] += 1.0 + a * a;  poldiv( polu, nn, polq, nn, polt ); /* divide into b */  polsbt( polt, nn, patan, nn, polu ); /* arctan(b)  */  polu[0] += t; /* plus arctan(a) */  polmov( polu, nn, ans );  free( polt );  free( polu );  free( polq );}/* Square root of a polynomial. * Assumes the lowest degree nonzero term is dominant * and of even degree.  An error message is given * if the Newton iteration does not converge. */voidpolsqt( pol, ans, nn )     double pol[], ans[];     int nn;{  double t;  double *x, *y;  int i, n;#if 0  double z[N+1];  double u;#endif  if (nn > N)    {      mtherr ("polatn", OVERFLOW);      return;    }  x = (double * )malloc( (MAXPOL+1) * sizeof (double) );  y = (double * )malloc( (MAXPOL+1) * sizeof (double) );  polmov( pol, nn, x );  polclr( y, MAXPOL );  /* Find lowest degree nonzero term.  */  t = 0.0;  for( n=0; n<nn; n++ )    {      if( x[n] != 0.0 )	goto nzero;    }  polmov( y, nn, ans );  return;nzero:  if( n > 0 )    {      if (n & 1)        {	  printf("error, sqrt of odd polynomial\n");	  return;	}      /* Divide by x^n.  */      y[n] = x[n];      poldiv (y, nn, pol, N, x);    }  t = x[0];  for( i=1; i<=nn; i++ )    x[i] /= t;  x[0] = 0.0;  /* series development sqrt(1+x) = 1  +  x / 2  -  x**2 / 8  +  x**3 / 16     hopes that first (constant) term is greater than what follows   */  polsbt( x, nn, psqrt, nn, y);  t = sqrt( t );  for( i=0; i<=nn; i++ )    y[i] *= t;  /* If first nonzero coefficient was at degree n > 0, multiply by     x^(n/2).  */  if (n > 0)    {      polclr (x, MAXPOL);      x[n/2] = 1.0;      polmul (x, nn, y, nn, y);    }#if 0/* Newton iterations */for( n=0; n<10; n++ )	{	poldiv( y, nn, pol, nn, z );	poladd( y, nn, z, nn, y );	for( i=0; i<=nn; i++ )		y[i] *= 0.5;	for( i=0; i<=nn; i++ )		{		u = fabs( y[i] - z[i] );		if( u > 1.0e-15 )			goto more;		}	goto done;more:	;	}printf( "square root did not converge\n" );done:#endif /* 0 */polmov( y, nn, ans );free( y );free( x );}/* Sine of a polynomial. * The computation uses *     sin(a+b) = sin(a) cos(b) + cos(a) sin(b) * where a is the constant term of the polynomial and * b is the sum of the rest of the terms. * Since sin(b) and cos(b) are computed by series expansions, * the value of b should be small. */voidpolsin( x, y, nn )     double x[], y[];     int nn;{  double a, sc;  double *w, *c;  int i;  if (nn > N)    {      mtherr ("polatn", OVERFLOW);      return;    }  w = (double * )malloc( (MAXPOL+1) * sizeof (double) );  c = (double * )malloc( (MAXPOL+1) * sizeof (double) );  polmov( x, nn, w );  polclr( c, MAXPOL );  polclr( y, nn );  /* a, in the description, is x[0].  b is the polynomial x - x[0].  */  a = w[0];  /* c = cos (b) */  w[0] = 0.0;  polsbt( w, nn, pcos, nn, c );  sc = sin(a);  /* sin(a) cos (b) */  for( i=0; i<=nn; i++ )    c[i] *= sc;  /* y = sin (b)  */  polsbt( w, nn, psin, nn, y );  sc = cos(a);  /* cos(a) sin(b) */  for( i=0; i<=nn; i++ )    y[i] *= sc;  poladd( c, nn, y, nn, y );  free( c );  free( w );}/* Cosine of a polynomial. * The computation uses *     cos(a+b) = cos(a) cos(b) - sin(a) sin(b) * where a is the constant term of the polynomial and * b is the sum of the rest of the terms. * Since sin(b) and cos(b) are computed by series expansions, * the value of b should be small. */voidpolcos( x, y, nn )     double x[], y[];     int nn;{  double a, sc;  double *w, *c;  int i;  double sin(), cos();  if (nn > N)    {      mtherr ("polatn", OVERFLOW);      return;    }  w = (double * )malloc( (MAXPOL+1) * sizeof (double) );  c = (double * )malloc( (MAXPOL+1) * sizeof (double) );  polmov( x, nn, w );  polclr( c, MAXPOL );  polclr( y, nn );  a = w[0];  w[0] = 0.0;  /* c = cos(b)  */  polsbt( w, nn, pcos, nn, c );  sc = cos(a);  /* cos(a) cos(b)  */  for( i=0; i<=nn; i++ )    c[i] *= sc;  /* y = sin(b) */  polsbt( w, nn, psin, nn, y );  sc = sin(a);  /* sin(a) sin(b) */  for( i=0; i<=nn; i++ )    y[i] *= sc;  polsub( y, nn, c, nn, y );  free( c );  free( w );}
 |