xref: /csrg-svn/usr.bin/f77/libF77/r_tan.c (revision 47940)
1*47940Sbostic /*-
2*47940Sbostic  * Copyright (c) 1980 The Regents of the University of California.
3*47940Sbostic  * All rights reserved.
422970Skre  *
5*47940Sbostic  * %sccs.include.proprietary.c%
610538Sdlw  */
710538Sdlw 
8*47940Sbostic #ifndef lint
9*47940Sbostic static char sccsid[] = "@(#)r_tan.c	5.5 (Berkeley) 04/12/91";
10*47940Sbostic #endif /* not lint */
11*47940Sbostic 
1229970Smckusick #ifndef tahoe
r_tan(x)1323854Sjerry float r_tan(x)
1410538Sdlw float *x;
1510538Sdlw {
1610538Sdlw double tan();
1710538Sdlw return( tan(*x) );
1810538Sdlw }
1929970Smckusick 
2029970Smckusick #else tahoe
2129970Smckusick 
2229970Smckusick /*
2329970Smckusick 	SINGLE PRECISION floating point tangent
2429970Smckusick 
2529970Smckusick 	sin/cos is used after argument reduction to [0,pi/4] range.
2629970Smckusick 	since x is in this range, tan(x) is in [0,1] range and
2729970Smckusick 	no overflow can occur here.
2829970Smckusick */
2929970Smckusick 
3029970Smckusick #include <errno.h>
3129970Smckusick 
3229970Smckusick int	errno;
3329970Smckusick static double invpi = 1.27323954473516268;  /* 4/pi */
3429970Smckusick 
3540229Sdonn #ifndef __GNUC__
3640229Sdonn fortran float sin(), cos();
3740229Sdonn #else
3840229Sdonn #define	sin(x) \
3940229Sdonn ({ \
4040229Sdonn 	float __result; \
4140229Sdonn 	asm("ldd %1; cvdf; sinf; stf %0" : "=rm" (__result) : "rm" (x)); \
4240229Sdonn 	__result; \
4340229Sdonn })
4440229Sdonn #define	cos(x) \
4540229Sdonn ({ \
4640229Sdonn 	float __result; \
4740229Sdonn 	asm("ldd %1; cvdf; cosf; stf %0" : "=rm" (__result) : "rm" (x)); \
4840229Sdonn 	__result; \
4940229Sdonn })
5040229Sdonn #endif
5140229Sdonn 
5229970Smckusick float
r_tan(parg)5329970Smckusick r_tan(parg)
5429970Smckusick float *parg;
5529970Smckusick {
5629970Smckusick 	double arg;
5729970Smckusick 	double modf();
5829970Smckusick 	float flmax_();
5929970Smckusick 	double temp, e, x, xsq;
6029970Smckusick 	int sign;
6129970Smckusick 	int flag, i;
6229970Smckusick 
6329970Smckusick 	arg = *parg;
6429970Smckusick 	flag = 0;
6529970Smckusick 	sign = 1.;
6629970Smckusick 	if(arg < 0.){		/* tan(-arg) = -tan(arg) */
6729970Smckusick 		arg = -arg;
6829970Smckusick 		sign = -1.;
6929970Smckusick 	}
7029970Smckusick 	arg = arg*invpi;   /*overflow?*/
7129970Smckusick 	x = modf(arg,&e);
7229970Smckusick 	i = e;
7329970Smckusick 	switch(i%4) {
7429970Smckusick 	case 1:			/* 2nd octant: tan(x) = 1/tan(1-x) */
7529970Smckusick 		x = 1. - x;
7629970Smckusick 		flag = 1;
7729970Smckusick 		break;
7829970Smckusick 
7929970Smckusick 	case 2:			/* 3rd octant: tan(x) = -1/tan(x) */
8029970Smckusick 		sign = - sign;
8129970Smckusick 		flag = 1;
8229970Smckusick 		break;
8329970Smckusick 
8429970Smckusick 	case 3:			/* 4th octant: tan(x) = -tan(1-x) */
8529970Smckusick 		x = 1. - x;
8629970Smckusick 		sign = - sign;
8729970Smckusick 		break;
8829970Smckusick 
8929970Smckusick 	case 0:			/* 1st octant */
9029970Smckusick 		break;
9129970Smckusick 	}
9229970Smckusick 	x = x/invpi;
9329970Smckusick 
9429970Smckusick 	temp = sin(x)/cos(x);
9529970Smckusick 
9629970Smckusick 	if(flag == 1) {
9729970Smckusick 		if(temp == 0.) {	/* check for singular "point" */
9829970Smckusick 			errno = ERANGE;
9929970Smckusick 			if (sign>0)
10029970Smckusick 				return(flmax_());
10129970Smckusick 			return(-flmax_());
10229970Smckusick 		}
10329970Smckusick 		temp = 1./temp;
10429970Smckusick 	}
10529970Smckusick 	return(sign*temp);
10629970Smckusick }
10729970Smckusick 
10829970Smckusick #endif tahoe
109