Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
c/lib/math/sin.c
There are 7 other files named sin.c in the archive. Click here to see a list.
/*
* +++ NAME +++
*
* SIN Double precision sine
*
* +++ INDEX +++
*
* SIN
* machine independent routines
* trigonometric functions
* math libraries
*
* +++ DESCRIPTION +++
*
* Returns double precision sine of double precision
* floating point argument.
*
* +++ USAGE +++
*
* double sin(x)
* double x;
*
* +++ REFERENCES +++
*
* Computer Approximations, J.F. Hart et al, John Wiley & Sons,
* 1968, pp. 112-120.
*
* +++ RESTRICTIONS +++
*
* The sin and cos routines are interactive in the sense that
* in the process of reducing the argument to the range -PI/4
* to PI/4, each may call the other. Ultimately one or the
* other uses a polynomial approximation on the reduced
* argument. The sin approximation has a maximum relative error
* of 10**(-17.59) and the cos approximation has a maximum
* relative error of 10**(-16.18).
*
* These error bounds assume exact arithmetic
* in the polynomial evaluation. Additional rounding and
* truncation errors may occur as the argument is reduced
* to the range over which the polynomial approximation
* is valid, and as the polynomial is evaluated using
* finite-precision arithmetic.
*
* +++ PROGRAMMER +++
*
* Fred Fish
* Goodyear Aerospace Corp, Arizona Div.
* (602) 932-7000 work
* (602) 894-6881 home
*
* Modifications for inclusion in standard C library are
* (c) Copyright Ian Macky, SRI International 1985
* Additional modifications after v.6, 19-Jan-1988 are
* (c) Copyright Ken Harrenstien 1989
*
* This routine now conforms with the description of the sin()
* function as defined in
* Harbison & Steele's "C: A Reference Manual", section 11.3.21
*
* +++ INTERNALS +++
*
* Computes sin(X) from:
*
* (1) Reduce argument X to range -PI to PI.
*
* (2) If X > PI/2 then call sin recursively
* using relation sin(X) = -sin(X - PI).
*
* (3) If X < -PI/2 then call sin recursively
* using relation sin(X) = -sin(X + PI).
*
* (4) If X > PI/4 then call cos using
* relation sin(X) = cos(PI/2 - X).
*
* (5) If X < -PI/4 then call cos using
* relation sin(X) = -cos(PI/2 + X).
*
* (6) If X is small enough that polynomial
* evaluation would cause underflow
* then return X, since sin(X)
* approaches X as X approaches zero.
*
* (7) By now X has been reduced to range
* -PI/4 to PI/4 and the approximation
* from HART pg. 118 can be used:
*
* sin(X) = Y * ( P(Y) / Q(Y) )
* Where:
*
* Y = X * (4/PI)
*
* P(Y) = SUM [ Pj * (Y**(2*j)) ]
* over j = {0,1,2,3}
*
* Q(Y) = SUM [ Qj * (Y**(2*j)) ]
* over j = {0,1,2,3}
*
* P0 = 0.206643433369958582409167054e+7
* P1 = -0.18160398797407332550219213e+6
* P2 = 0.359993069496361883172836e+4
* P3 = -0.2010748329458861571949e+2
* Q0 = 0.263106591026476989637710307e+7
* Q1 = 0.3927024277464900030883986e+5
* Q2 = 0.27811919481083844087953e+3
* Q3 = 1.0000...
* (coefficients from HART table #3063 pg 234)
*
*
* **** NOTE **** The range reduction relations used in
* this routine depend on the final approximation being valid
* over the negative argument range in addition to the positive
* argument range. The particular approximation chosen from
* HART satisfies this requirement, although not explicitly
* stated in the text. This may not be true of other
* approximations given in the reference.
*
* ---
*/
#include <math.h>
#include "pml.h"
static double sin_pcoeffs[] = {
0.20664343336995858240e7,
-0.18160398797407332550e6,
0.35999306949636188317e4,
-0.20107483294588615719e2
};
static double sin_qcoeffs[] = {
0.26310659102647698963e7,
0.39270242774649000308e5,
0.27811919481083844087e3,
1.0
};
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
double sin(x)
double x;
{
double y, yt2;
if (x < -PI || x > PI) {
x = fmod(x, TWOPI);
if (x > PI) {
x = x - TWOPI;
} else if (x < -PI) {
x = x + TWOPI;
}
}
/* Use MAX and MIN to avoid infinite recursion which can
occur if x = HALFPI + eps, and (x - PI) = HALFPI - eps */
if (x > HALFPI)
return -sin(MAX(-HALFPI, x - PI));
else if (x < -HALFPI)
return -sin(MIN(PI, x + PI));
else if (x > FOURTHPI)
return cos(HALFPI - x);
else if (x < -FOURTHPI)
return -cos(HALFPI + x);
else if (x < X6_UNDERFLOWS && x > -X6_UNDERFLOWS)
return x;
else {
y = x / FOURTHPI;
yt2 = y * y;
return y * _poly4(sin_pcoeffs, yt2) / _poly4(sin_qcoeffs, yt2);
}
}