⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xcmstrig.c

📁 早期freebsd实现
💻 C
字号:
/* $XConsortium: XcmsTrig.c,v 1.4 91/11/05 11:02:20 rws Exp $" *//* * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc. * 	All Rights Reserved *  * This file is a component of an X Window System-specific implementation * of Xcms based on the TekColor Color Management System.  Permission is * hereby granted to use, copy, modify, sell, and otherwise distribute this * software and its documentation for any purpose and without fee, provided * that this copyright, permission, and disclaimer notice is reproduced in * all copies of this software and in supporting documentation.  TekColor * is a trademark of Tektronix, Inc. *  * Tektronix makes no representation about the suitability of this software * for any purpose.  It is provided "as is" and with all faults. *  * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. *//* *	It should be pointed out that for simplicity's sake, the *	environment parameters are defined as floating point constants, *	rather than octal or hexadecimal initializations of allocated *	storage areas.  This means that the range of allowed numbers *	may not exactly match the hardware's capabilities.  For example, *	if the maximum positive double precision floating point number *	is EXACTLY 1.11...E100 and the constant "MAXDOUBLE is *	defined to be 1.11E100 then the numbers between 1.11E100 and *	1.11...E100 are considered to be undefined.  For most *	applications, this will cause no problems. * *	An alternate method is to allocate a global static "double" variable, *	say "maxdouble", and use a union declaration and initialization *	to initialize it with the proper bits for the EXACT maximum value. *	This was not done because the only compilers available to the *	author did not fully support union initialization features. * *//* *	EXTERNS */extern double _XcmsSquareRoot();/* *	FORWARD DECLARATIONS */double _XcmsCosine();static double _XcmsModulo();static double _XcmsModuloF();static double _XcmsPolynomial();double _XcmsSine();double _XcmsArcTangent();/* *	DEFINES */#define XCMS_MAXERROR       	0.000001#define XCMS_MAXITER       	10000#define XCMS_PI       		3.14159265358979323846264338327950#define XCMS_TWOPI 		6.28318530717958620#define XCMS_HALFPI		1.57079632679489660#define XCMS_FOURTHPI		0.785398163397448280#define XCMS_SIXTHPI		0.523598775598298820#define XCMS_RADIANS(d)		((d) * XCMS_PI / 180.0)#define XCMS_DEGREES(r)		((r) * 180.0 / XCMS_PI)#define XCMS_X6_UNDERFLOWS	(4.209340e-52)	/* X**6 almost underflows */#define XCMS_X16_UNDERFLOWS	(5.421010e-20)	/* X**16 almost underflows*/#define XCMS_CHAR_BIT		8#define XCMS_LONG_MAX		0x7FFFFFFF#define XCMS_DEXPLEN		11#define XCMS_NBITS(type)	(XCMS_CHAR_BIT * (int)sizeof(type))#define XCMS_FABS(x)		((x) < 0.0 ? -(x) : (x))/* XCMS_DMAXPOWTWO - largest power of two exactly representable as a double */#define XCMS_DMAXPOWTWO	((double)(XCMS_LONG_MAX) * \	    (1L << (XCMS_NBITS(double)-XCMS_DEXPLEN) - XCMS_NBITS(long) + 1))/* *	LOCAL VARIABLES */static double cos_pcoeffs[] = {    0.12905394659037374438e7,   -0.37456703915723204710e6,    0.13432300986539084285e5,   -0.11231450823340933092e3};static double cos_qcoeffs[] = {    0.12905394659037373590e7,    0.23467773107245835052e5,    0.20969518196726306286e3,    1.0};static double sin_pcoeffs[] = {    0.20664343336995858240e7,   -0.18160398797407332550e6,    0.35999306949636188317e4,   -0.20107483294588615719e2};static double sin_qcoeffs[] = {    0.26310659102647698963e7,    0.39270242774649000308e5,    0.27811919481083844087e3,    1.0};/* * *  FUNCTION * *	_XcmsCosine   double precision cosine * *  KEY WORDS * *	cos *	machine independent routines *	trigonometric functions *	math libraries * *  DESCRIPTION * *	Returns double precision cosine of double precision *	floating point argument. * *  USAGE * *	double _XcmsCosine (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 * *  INTERNALS * *	Computes cos(x) from: * *		(1)	Reduce argument x to range -PI to PI. * *		(2)	If x > PI/2 then call cos recursively *			using relation cos(x) = -cos(x - PI). * *		(3)	If x < -PI/2 then call cos recursively *			using relation cos(x) = -cos(x + PI). * *		(4)	If x > PI/4 then call sin using *			relation cos(x) = sin(PI/2 - x). * *		(5)	If x < -PI/4 then call cos using *			relation cos(x) = sin(PI/2 + x). * *		(6)	If x would cause underflow in approx *			evaluation arithmetic then return *			sqrt(1.0 - x**2). * *		(7)	By now x has been reduced to range *			-PI/4 to PI/4 and the approximation *			from HART pg. 119 can be used: * *			cos(x) = ( 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.12905394659037374438571854e+7 *			P1   =	-0.3745670391572320471032359e+6 *			P2   =	0.134323009865390842853673e+5 *			P3   =	-0.112314508233409330923e+3 *			Q0   =	0.12905394659037373590295914e+7 *			Q1   =	0.234677731072458350524124e+5 *			Q2   =	0.2096951819672630628621e+3 *			Q3   =	1.0000... *			(coefficients from HART table #3843 pg 244) * * *	**** 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. *			 */double _XcmsCosine (x)double x;{    auto double y;    auto double yt2;    double retval;    if (x < -XCMS_PI || x > XCMS_PI) {	x = _XcmsModulo (x, XCMS_TWOPI);        if (x > XCMS_PI) {	    x = x - XCMS_TWOPI;        } else if (x < -XCMS_PI) {	    x = x + XCMS_TWOPI;        }    }    if (x > XCMS_HALFPI) {	retval = -(_XcmsCosine (x - XCMS_PI));    } else if (x < -XCMS_HALFPI) {	retval = -(_XcmsCosine (x + XCMS_PI));    } else if (x > XCMS_FOURTHPI) {	retval = _XcmsSine (XCMS_HALFPI - x);    } else if (x < -XCMS_FOURTHPI) {	retval = _XcmsSine (XCMS_HALFPI + x);    } else if (x < XCMS_X6_UNDERFLOWS && x > -XCMS_X6_UNDERFLOWS) {	retval = _XcmsSquareRoot (1.0 - (x * x));    } else {	y = x / XCMS_FOURTHPI;	yt2 = y * y;	retval = _XcmsPolynomial (3, cos_pcoeffs, yt2) / _XcmsPolynomial (3, cos_qcoeffs, yt2);    }    return (retval);}/* *  FUNCTION * *	_XcmsModulo   double precision modulo * *  KEY WORDS * *	_XcmsModulo *	machine independent routines *	math libraries * *  DESCRIPTION * *	Returns double precision modulo of two double *	precision arguments. * *  USAGE * *	double _XcmsModulo (value, base) *	double value; *	double base; * *  PROGRAMMER * *	Fred Fish * */static double _XcmsModulo (value, base)double value;double base;{    auto double intpart;    value /= base;    value = _XcmsModuloF (value, &intpart);    value *= base;    return(value);}/* * frac = (double) _XcmsModuloF(double val, double *dp) *	return fractional part of 'val' *	set *dp to integer part of 'val' * * Note  -> only compiled for the CA or KA.  For the KB/MC, * "math.c" instantiates a copy of the inline function * defined in "math.h". */static double_XcmsModuloF(val, dp)double val;register double *dp;{	register double abs;	register double ip;	/* should check for illegal values here - nan, inf, etc */	abs = XCMS_FABS(val);	if (abs >= XCMS_DMAXPOWTWO) {		ip = val;	} else {		ip = abs + XCMS_DMAXPOWTWO;	/* dump fraction */		ip -= XCMS_DMAXPOWTWO;	/* restore w/o frac */		if (ip > abs)		/* if it rounds up */			ip -= 1.0;	/* fix it */		ip = XCMS_FABS(ip);	}	*dp = ip;	return (val - ip); /* signed fractional part */}/* *  FUNCTION * *	_XcmsPolynomial   double precision polynomial evaluation * *  KEY WORDS * *	poly *	machine independent routines *	math libraries * *  DESCRIPTION * *	Evaluates a polynomial and returns double precision *	result.  Is passed a the order of the polynomial, *	a pointer to an array of double precision polynomial *	coefficients (in ascending order), and the independent *	variable. * *  USAGE * *	double _XcmsPolynomial (order, coeffs, x) *	int order; *	double *coeffs; *	double x; * *  PROGRAMMER * *	Fred Fish * *  INTERNALS * *	Evalates the polynomial using recursion and the form: * *		P(x) = P0 + x(P1 + x(P2 +...x(Pn))) * */static double _XcmsPolynomial (order, coeffs, x)register int order;double *coeffs;double x;{    auto double rtn_value;#if 0    auto double curr_coeff;    if (order <= 0) {	rtn_value = *coeffs;    } else {	curr_coeff = *coeffs;	/* Bug in Unisoft's compiler.  Does not */	coeffs++;		/* generate good code for *coeffs++ */	rtn_value = curr_coeff + x * _XcmsPolynomial (--order, coeffs, x);    }#else /* ++jrb -- removed tail recursion */    coeffs += order;    rtn_value = *coeffs--;    while(order-- > 0)	rtn_value = *coeffs-- + (x * rtn_value);#endif    return(rtn_value);}/* *  FUNCTION * *	_XcmsSine	double precision sine * *  KEY WORDS * *	sin *	machine independent routines *	trigonometric functions *	math libraries * *  DESCRIPTION * *	Returns double precision sine of double precision *	floating point argument. * *  USAGE * *	double _XcmsSine (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 * *  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. *			 */double_XcmsSine (x)double x;{    double y;    double yt2;    double retval;    if (x < -XCMS_PI || x > XCMS_PI) {	x = _XcmsModulo (x, XCMS_TWOPI);	if (x > XCMS_PI) {	    x = x - XCMS_TWOPI;	} else if (x < -XCMS_PI) {	    x = x + XCMS_TWOPI;	}    }    if (x > XCMS_HALFPI) {	retval = -(_XcmsSine (x - XCMS_PI));    } else if (x < -XCMS_HALFPI) {	retval = -(_XcmsSine (x + XCMS_PI));    } else if (x > XCMS_FOURTHPI) {	retval = _XcmsCosine (XCMS_HALFPI - x);    } else if (x < -XCMS_FOURTHPI) {	retval = -(_XcmsCosine (XCMS_HALFPI + x));    } else if (x < XCMS_X6_UNDERFLOWS && x > -XCMS_X6_UNDERFLOWS) {	retval = x;    } else {	y = x / XCMS_FOURTHPI;	yt2 = y * y;	retval = y * (_XcmsPolynomial (3, sin_pcoeffs, yt2) / _XcmsPolynomial(3, sin_qcoeffs, yt2));    }    return(retval);}/* *	NAME *		_XcmsArcTangent * *	SYNOPSIS */double_XcmsArcTangent(x)    double x;/* *	DESCRIPTION *		Computes the arctangent. *		This is an implementation of the Gauss algorithm as *		described in: *		    Forman S. Acton, Numerical Methods That Work, *			New York, NY, Harper & Row, 1970. * *	RETURNS *		Returns the arctangent  */{    double ai, a1, bi, b1, l, d;    double maxerror;    int i;    if (x == 0.0)  {	return (0.0);    }    if (x < 1.0) {	maxerror = x * XCMS_MAXERROR;    } else {	maxerror = XCMS_MAXERROR;    }    ai = _XcmsSquareRoot( 1.0 / (1.0 + (x * x)) );    bi = 1.0;    for (i = 0; i < XCMS_MAXITER; i++) {	a1 = (ai + bi) / 2.0;	b1 = _XcmsSquareRoot((a1 * bi));	if (a1 == b1)	    break;	d = XCMS_FABS(a1 - b1);	if (d < maxerror)	    break;	ai = a1;	bi = b1;    }    l = ((a1 > b1) ? b1 : a1);    a1 = _XcmsSquareRoot(1 + (x * x));    return (x / (a1 * l));}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -