Added
Link Here
|
1 |
/*- |
2 |
* Copyright (c) 2017 Steven G. Kargl |
3 |
* All rights reserved. |
4 |
* |
5 |
* Redistribution and use in source and binary forms, with or without |
6 |
* modification, are permitted provided that the following conditions |
7 |
* are met: |
8 |
* 1. Redistributions of source code must retain the above copyright |
9 |
* notice unmodified, this list of conditions, and the following |
10 |
* disclaimer. |
11 |
* 2. Redistributions in binary form must reproduce the above copyright |
12 |
* notice, this list of conditions and the following disclaimer in the |
13 |
* documentation and/or other materials provided with the distribution. |
14 |
* |
15 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
16 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
17 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
18 |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
19 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
20 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
21 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
22 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
23 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
24 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 |
*/ |
26 |
|
27 |
/** |
28 |
* tanpi(x) computes tan(pi*x) without multiplication by pi (almost). First, |
29 |
* note that tanpi(-x) = -tanpi(x), so the algorithm considers only |x| and |
30 |
* includes reflection symmetry by considering the sign of x on output. The |
31 |
* method used depends on the magnitude of x. |
32 |
* |
33 |
* 1. For small |x|, tanpi(x) = pi * x where a sloppy threshold is used. The |
34 |
* threshold is |x| < 0x1pN with N = -(P/2+M). P is the precision of the |
35 |
* floating-point type and M = 2 to 4. To achieve high accuracy, pi is |
36 |
* decomposed into high and low parts with the high part containing a |
37 |
* number of trailing zero bits. x is also split into high and low parts. |
38 |
* |
39 |
* 2. For |x| < 1, argument reduction is not required and tanpi(x) is |
40 |
* computed by a direct call to a kernel, which uses the kernel for |
41 |
* tan(x). See below. |
42 |
* |
43 |
* 3. For 1 <= |x| < 0x1p(P-1), argument reduction is required where |
44 |
* |x| = j0 + r with j0 an integer and the remainder r satisfies |
45 |
* 0 <= r < 1. With the given domain, a simplified inline floor(x) |
46 |
* is used. Also, note the following identity |
47 |
* |
48 |
* tan(pi*j0) + tan(pi*r) |
49 |
* tanpi(x) = tan(pi*(j0+r)) = ---------------------------- = tanpi(r) |
50 |
* 1 - tan(pi*j0) * tan(pi*r) |
51 |
* |
52 |
* So, after argument reduction, the kernel is again invoked. |
53 |
* |
54 |
* 4. For |x| >= 0x1p(P-1), |x| is integral and tanpi(x) = copysign(0,x). |
55 |
* |
56 |
* 5. Special cases: |
57 |
* |
58 |
* tanpi(+-0) = +-0 |
59 |
* tanpi(+-n) = +-0, for positive integers n. |
60 |
* tanpi(+-n+1/4) = +-1, for positive integers n. |
61 |
* tanpi(+-n+1/2) = NaN, for positive integers n. |
62 |
* tanpi(+-inf) = NaN. Raises the "invalid" floating-point exception. |
63 |
* tanpi(nan) = NaN. Raises the "invalid" floating-point exception. |
64 |
*/ |
65 |
|
66 |
#include "math.h" |
67 |
#include "math_private.h" |
68 |
|
69 |
static const double |
70 |
pi_hi = 3.1415926814079285e+00, /* 0x400921fb 0x58000000 */ |
71 |
pi_lo = -2.7818135228334233e-08; /* 0xbe5dde97 0x3dcb3b3a */ |
72 |
|
73 |
/* |
74 |
* The kernel for tanpi(x) multiplies x by an 80-bit approximation of |
75 |
* pi, where the hi and lo parts are used with with kernel for tan(x). |
76 |
*/ |
77 |
static inline double |
78 |
__kernel_tanpi(double x) |
79 |
{ |
80 |
double_t hi, lo, t; |
81 |
|
82 |
if (x < 0.25) { |
83 |
hi = (float)x; |
84 |
lo = x - hi; |
85 |
lo = lo * (pi_lo + pi_hi) + hi * pi_lo; |
86 |
hi *= pi_hi; |
87 |
_2sumF(hi, lo); |
88 |
t = __kernel_tan(hi, lo, 1); |
89 |
} else if (x > 0.25) { |
90 |
x = 0.5 - x; |
91 |
hi = (float)x; |
92 |
lo = x - hi; |
93 |
lo = lo * (pi_lo + pi_hi) + hi * pi_lo; |
94 |
hi *= pi_hi; |
95 |
_2sumF(hi, lo); |
96 |
t = - __kernel_tan(hi, lo, -1); |
97 |
} else |
98 |
t = 1; |
99 |
|
100 |
return (t); |
101 |
} |
102 |
|
103 |
volatile static const double vzero = 0; |
104 |
|
105 |
double |
106 |
tanpi(double x) |
107 |
{ |
108 |
double ax, hi, lo, t; |
109 |
uint32_t hx, ix, j0, lx; |
110 |
|
111 |
EXTRACT_WORDS(hx, lx, x); |
112 |
ix = hx & 0x7fffffff; |
113 |
INSERT_WORDS(ax, ix, lx); |
114 |
|
115 |
if (ix < 0x3ff00000) { /* |x| < 1 */ |
116 |
if (ix < 0x3fe00000) { /* |x| < 0.5 */ |
117 |
if (ix < 0x3e200000) { /* |x| < 0x1p-29 */ |
118 |
if (x == 0) |
119 |
return (x); |
120 |
/* |
121 |
* To avoid issues with subnormal values, |
122 |
* scale the computation and rescale on |
123 |
* return. |
124 |
*/ |
125 |
INSERT_WORDS(hi, hx, 0); |
126 |
hi *= 0x1p53; |
127 |
lo = x * 0x1p53 - hi; |
128 |
t = (pi_lo + pi_hi) * lo + pi_lo * hi + |
129 |
pi_hi * hi; |
130 |
return (t * 0x1p-53); |
131 |
} |
132 |
t = __kernel_tanpi(ax); |
133 |
} else if (ax == 0.5) |
134 |
return ((ax - ax) / (ax - ax)); |
135 |
else |
136 |
t = - __kernel_tanpi(1 - ax); |
137 |
return ((hx & 0x80000000) ? -t : t); |
138 |
} |
139 |
|
140 |
if (ix < 0x43300000) { /* 1 <= |x| < 0x1p52 */ |
141 |
/* Determine integer part of ax. */ |
142 |
j0 = ((ix >> 20) & 0x7ff) - 0x3ff; |
143 |
if (j0 < 20) { |
144 |
ix &= ~(0x000fffff >> j0); |
145 |
lx = 0; |
146 |
} else { |
147 |
lx &= ~(((uint32_t)(0xffffffff)) >> (j0 - 20)); |
148 |
} |
149 |
INSERT_WORDS(x,ix,lx); |
150 |
|
151 |
ax -= x; |
152 |
EXTRACT_WORDS(ix, lx, ax); |
153 |
|
154 |
if (ix < 0x3fe00000) /* |x| < 0.5 */ |
155 |
t = ax == 0 ? 0 : __kernel_tanpi(ax); |
156 |
else if (ax == 0.5) |
157 |
return ((ax - ax) / (ax - ax)); |
158 |
else |
159 |
t = - __kernel_tanpi(1 - ax); |
160 |
|
161 |
return ((hx & 0x80000000) ? -t : t); |
162 |
} |
163 |
|
164 |
/* x = +-inf or nan. */ |
165 |
if (ix >= 0x7f800000) |
166 |
return (vzero / vzero); |
167 |
|
168 |
/* |
169 |
* |x| >= 0x1p52 is always an integer, so return +-0. |
170 |
*/ |
171 |
return (copysign(0, x)); |
172 |
} |
173 |
|
174 |
#if LDBL_MANT_DIG == 53 |
175 |
__weak_reference(tanpi, tanpil); |
176 |
#endif |