1994-08-19 09:40:01 +00:00
|
|
|
/* @(#)s_tan.c 5.1 93/09/24 */
|
|
|
|
/*
|
|
|
|
* ====================================================
|
|
|
|
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
|
|
|
* Permission to use, copy, modify, and distribute this
|
1995-05-30 05:51:47 +00:00
|
|
|
* software is freely granted, provided that this notice
|
1994-08-19 09:40:01 +00:00
|
|
|
* is preserved.
|
|
|
|
* ====================================================
|
|
|
|
*/
|
|
|
|
|
2008-02-18 14:02:12 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
1994-08-19 09:40:01 +00:00
|
|
|
|
|
|
|
/* tan(x)
|
|
|
|
* Return tangent function of x.
|
|
|
|
*
|
|
|
|
* kernel function:
|
|
|
|
* __kernel_tan ... tangent function on [-pi/4,pi/4]
|
|
|
|
* __ieee754_rem_pio2 ... argument reduction routine
|
|
|
|
*
|
|
|
|
* Method.
|
1995-05-30 05:51:47 +00:00
|
|
|
* Let S,C and T denote the sin, cos and tan respectively on
|
|
|
|
* [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
|
1994-08-19 09:40:01 +00:00
|
|
|
* in [-pi/4 , +pi/4], and let n = k mod 4.
|
|
|
|
* We have
|
|
|
|
*
|
|
|
|
* n sin(x) cos(x) tan(x)
|
|
|
|
* ----------------------------------------------------------
|
|
|
|
* 0 S C T
|
|
|
|
* 1 C -S -1/T
|
|
|
|
* 2 -S -C T
|
|
|
|
* 3 -C S -1/T
|
|
|
|
* ----------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Special cases:
|
|
|
|
* Let trig be any of sin, cos, or tan.
|
|
|
|
* trig(+-INF) is NaN, with signals;
|
|
|
|
* trig(NaN) is that NaN;
|
|
|
|
*
|
|
|
|
* Accuracy:
|
1995-05-30 05:51:47 +00:00
|
|
|
* TRIG(x) returns trig(x) nearly rounded
|
1994-08-19 09:40:01 +00:00
|
|
|
*/
|
|
|
|
|
2008-02-17 07:33:12 +00:00
|
|
|
#include <float.h>
|
|
|
|
|
1994-08-19 09:40:01 +00:00
|
|
|
#include "math.h"
|
2008-02-18 14:02:12 +00:00
|
|
|
#define INLINE_REM_PIO2
|
1994-08-19 09:40:01 +00:00
|
|
|
#include "math_private.h"
|
2008-02-18 14:02:12 +00:00
|
|
|
#include "e_rem_pio2.c"
|
1994-08-19 09:40:01 +00:00
|
|
|
|
2002-05-28 18:15:04 +00:00
|
|
|
double
|
2003-07-23 04:53:47 +00:00
|
|
|
tan(double x)
|
1994-08-19 09:40:01 +00:00
|
|
|
{
|
|
|
|
double y[2],z=0.0;
|
|
|
|
int32_t n, ix;
|
|
|
|
|
|
|
|
/* High word of x. */
|
|
|
|
GET_HIGH_WORD(ix,x);
|
|
|
|
|
|
|
|
/* |x| ~< pi/4 */
|
|
|
|
ix &= 0x7fffffff;
|
Moved the optimization for tiny x from __kernel_tan[f](x) to tan[f](x)
so that it can be faster for tiny x and avoided for reduced x.
This improves things a little differently than for cosine and sine.
We still need to reclassify x in the "kernel" functions, but we get
an extra optimization for tiny x, and an overall optimization since
tiny reduced x rarely happens. We also get optimizations for space
and style. A large block of poorly duplicated code to fix a special
case is no longer needed. This supersedes the fixes in k_sin.c revs
1.9 and 1.11 and k_sinf.c 1.8 and 1.10.
Fixed wrong constant for the cutoff for "tiny" in tanf(). It was
2**-28, but should be almost the same as the cutoff in sinf() (2**-12).
The incorrect cutoff protected us from the bugs fixed in k_sinf.c 1.8
and 1.10, except 4 cases of reduced args passed the cutoff and needed
special handling in theory although not in practice. Now we essentially
use a cutoff of 0 for the case of reduced args, so we now have 0 special
args instead of 4.
This change makes no difference to the results for sinf() (since it
only changes the algorithm for the 4 special args and the results for
those happen not to change), but it changes lots of results for sin().
Exhaustive testing is impossible for sin(), but exhaustive testing
for sinf() (relative to a version with the old algorithm and a fixed
cutoff) shows that the changes in the error are either reductions or
from 0.5-epsilon ulps to 0.5+epsilon ulps. The new method just uses
some extra terms in approximations so it tends to give more accurate
results, and there are apparently no problems from having extra
accuracy. On amd64 with -O1, on all float args the error range in ulps
is reduced from (0.500, 0.665] to [0.335, 0.500) in 24168 cases and
increased from 0.500-epsilon to 0.500+epsilon in 24 cases. Non-
exhaustive testing by ucbtest shows no differences.
2005-11-02 14:01:45 +00:00
|
|
|
if(ix <= 0x3fe921fb) {
|
2011-02-10 07:37:50 +00:00
|
|
|
if(ix<0x3e400000) /* x < 2**-27 */
|
Moved the optimization for tiny x from __kernel_tan[f](x) to tan[f](x)
so that it can be faster for tiny x and avoided for reduced x.
This improves things a little differently than for cosine and sine.
We still need to reclassify x in the "kernel" functions, but we get
an extra optimization for tiny x, and an overall optimization since
tiny reduced x rarely happens. We also get optimizations for space
and style. A large block of poorly duplicated code to fix a special
case is no longer needed. This supersedes the fixes in k_sin.c revs
1.9 and 1.11 and k_sinf.c 1.8 and 1.10.
Fixed wrong constant for the cutoff for "tiny" in tanf(). It was
2**-28, but should be almost the same as the cutoff in sinf() (2**-12).
The incorrect cutoff protected us from the bugs fixed in k_sinf.c 1.8
and 1.10, except 4 cases of reduced args passed the cutoff and needed
special handling in theory although not in practice. Now we essentially
use a cutoff of 0 for the case of reduced args, so we now have 0 special
args instead of 4.
This change makes no difference to the results for sinf() (since it
only changes the algorithm for the 4 special args and the results for
those happen not to change), but it changes lots of results for sin().
Exhaustive testing is impossible for sin(), but exhaustive testing
for sinf() (relative to a version with the old algorithm and a fixed
cutoff) shows that the changes in the error are either reductions or
from 0.5-epsilon ulps to 0.5+epsilon ulps. The new method just uses
some extra terms in approximations so it tends to give more accurate
results, and there are apparently no problems from having extra
accuracy. On amd64 with -O1, on all float args the error range in ulps
is reduced from (0.500, 0.665] to [0.335, 0.500) in 24168 cases and
increased from 0.500-epsilon to 0.500+epsilon in 24 cases. Non-
exhaustive testing by ucbtest shows no differences.
2005-11-02 14:01:45 +00:00
|
|
|
if((int)x==0) return x; /* generate inexact */
|
|
|
|
return __kernel_tan(x,z,1);
|
|
|
|
}
|
1994-08-19 09:40:01 +00:00
|
|
|
|
|
|
|
/* tan(Inf or NaN) is NaN */
|
|
|
|
else if (ix>=0x7ff00000) return x-x; /* NaN */
|
|
|
|
|
|
|
|
/* argument reduction needed */
|
|
|
|
else {
|
|
|
|
n = __ieee754_rem_pio2(x,y);
|
|
|
|
return __kernel_tan(y[0],y[1],1-((n&1)<<1)); /* 1 -- n even
|
|
|
|
-1 -- n odd */
|
|
|
|
}
|
|
|
|
}
|
2008-02-17 07:33:12 +00:00
|
|
|
|
|
|
|
#if (LDBL_MANT_DIG == 53)
|
|
|
|
__weak_reference(tan, tanl);
|
|
|
|
#endif
|