1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)r_tan.c 5.3 11/03/86 7 */ 8 9 #ifndef tahoe 10 float r_tan(x) 11 float *x; 12 { 13 double tan(); 14 return( tan(*x) ); 15 } 16 17 #else tahoe 18 19 /* 20 SINGLE PRECISION floating point tangent 21 22 sin/cos is used after argument reduction to [0,pi/4] range. 23 since x is in this range, tan(x) is in [0,1] range and 24 no overflow can occur here. 25 */ 26 27 #include <errno.h> 28 29 int errno; 30 static double invpi = 1.27323954473516268; /* 4/pi */ 31 32 float 33 r_tan(parg) 34 float *parg; 35 { 36 double arg; 37 fortran float sin(), cos(); 38 double modf(); 39 float flmax_(); 40 double temp, e, x, xsq; 41 int sign; 42 int flag, i; 43 44 arg = *parg; 45 flag = 0; 46 sign = 1.; 47 if(arg < 0.){ /* tan(-arg) = -tan(arg) */ 48 arg = -arg; 49 sign = -1.; 50 } 51 arg = arg*invpi; /*overflow?*/ 52 x = modf(arg,&e); 53 i = e; 54 switch(i%4) { 55 case 1: /* 2nd octant: tan(x) = 1/tan(1-x) */ 56 x = 1. - x; 57 flag = 1; 58 break; 59 60 case 2: /* 3rd octant: tan(x) = -1/tan(x) */ 61 sign = - sign; 62 flag = 1; 63 break; 64 65 case 3: /* 4th octant: tan(x) = -tan(1-x) */ 66 x = 1. - x; 67 sign = - sign; 68 break; 69 70 case 0: /* 1st octant */ 71 break; 72 } 73 x = x/invpi; 74 75 temp = sin(x)/cos(x); 76 77 if(flag == 1) { 78 if(temp == 0.) { /* check for singular "point" */ 79 errno = ERANGE; 80 if (sign>0) 81 return(flmax_()); 82 return(-flmax_()); 83 } 84 temp = 1./temp; 85 } 86 return(sign*temp); 87 } 88 89 #endif tahoe 90