|
|
1.1 ! root 1: /* @(#)r_tan.c 1.0 10/01/82 */ ! 2: ! 3: /* ! 4: SINGLE PRECISION floating point tangent ! 5: ! 6: sin/cos is used after argument reduction to [0,pi/4] range. ! 7: since x is in this range, tan(x) is in [0,1] range and ! 8: no overflow can occur here. ! 9: */ ! 10: ! 11: #include <errno.h> ! 12: ! 13: int errno; ! 14: static double invpi = 1.27323954473516268; /* 4/pi */ ! 15: ! 16: float ! 17: r_tan(parg) ! 18: float *parg; ! 19: { ! 20: double arg; ! 21: fortran float sin(), cos(); ! 22: double modf(); ! 23: float flmax_(); ! 24: double temp, e, x, xsq; ! 25: int sign; ! 26: int flag, i; ! 27: ! 28: arg = *parg; ! 29: flag = 0; ! 30: sign = 1.; ! 31: if(arg < 0.){ /* tan(-arg) = -tan(arg) */ ! 32: arg = -arg; ! 33: sign = -1.; ! 34: } ! 35: arg = arg*invpi; /*overflow?*/ ! 36: x = modf(arg,&e); ! 37: i = e; ! 38: switch(i%4) { ! 39: case 1: /* 2nd octant: tan(x) = 1/tan(1-x) */ ! 40: x = 1. - x; ! 41: flag = 1; ! 42: break; ! 43: ! 44: case 2: /* 3rd octant: tan(x) = -1/tan(x) */ ! 45: sign = - sign; ! 46: flag = 1; ! 47: break; ! 48: ! 49: case 3: /* 4th octant: tan(x) = -tan(1-x) */ ! 50: x = 1. - x; ! 51: sign = - sign; ! 52: break; ! 53: ! 54: case 0: /* 1st octant */ ! 55: break; ! 56: } ! 57: x = x/invpi; ! 58: ! 59: temp = sin(x)/cos(x); ! 60: ! 61: if(flag == 1) { ! 62: if(temp == 0.) { /* check for singular "point" */ ! 63: errno = ERANGE; ! 64: if (sign>0) ! 65: return(flmax_()); ! 66: return(-flmax_()); ! 67: } ! 68: temp = 1./temp; ! 69: } ! 70: return(sign*temp); ! 71: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.