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)1323854Sjerryfloat 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)5329970Smckusickr_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