|
Line 0
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 |
pihi = 3.1415926814079285e+00, /* 0x400921fb 0x58000000 */ |
| 71 |
pilo = -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 hi, lo, t; |
| 81 |
|
| 82 |
if (x < 0.25) { |
| 83 |
hi = (float)x; |
| 84 |
lo = x - hi; |
| 85 |
lo = lo * (pilo + pihi) + hi * pilo; |
| 86 |
hi *= pihi; |
| 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 * (pilo + pihi) + hi * pilo; |
| 94 |
hi *= pihi; |
| 95 |
_2sumF(hi, lo); |
| 96 |
t = - __kernel_tan(hi, lo, -1); |
| 97 |
} else |
| 98 |
t = 1; |
| 99 |
|
| 100 |
return (t); |
| 101 |
} |
| 102 |
|
| 103 |
double |
| 104 |
tanpi(double x) |
| 105 |
{ |
| 106 |
volatile static const double vzero = 0; |
| 107 |
double ax, t; |
| 108 |
uint32_t hx, ix, j0, lx; |
| 109 |
|
| 110 |
EXTRACT_WORDS(hx, lx, x); |
| 111 |
ix = hx & 0x7fffffff; |
| 112 |
INSERT_WORDS(ax, ix, lx); |
| 113 |
|
| 114 |
if (ix < 0x3ff00000) { /* |x| < 1 */ |
| 115 |
if (ix < 0x3fe00000) { /* |x| < 0.5 */ |
| 116 |
if (ix < 0x3e200000) { /* |x| < 0x1p-29 */ |
| 117 |
if (x == 0) |
| 118 |
return (x); |
| 119 |
ax = (float)x; |
| 120 |
x -= ax; |
| 121 |
t = pilo * x + pihi * x + pilo * ax |
| 122 |
+ pihi * ax; |
| 123 |
return (t); |
| 124 |
} |
| 125 |
t = __kernel_tanpi(ax); |
| 126 |
} else if (ax == 0.5) |
| 127 |
return ((ax - ax) / (ax - ax)); |
| 128 |
else |
| 129 |
t = - __kernel_tanpi(1 - ax); |
| 130 |
return ((hx & 0x80000000) ? -t : t); |
| 131 |
} |
| 132 |
|
| 133 |
if (ix < 0x43300000) { /* 1 <= |x| < 0x1p52 */ |
| 134 |
/* Determine integer part of ax. */ |
| 135 |
j0 = ((ix >> 20) & 0x7ff) - 0x3ff; |
| 136 |
if (j0 < 20) { |
| 137 |
ix &= ~(0x000fffff >> j0); |
| 138 |
lx = 0; |
| 139 |
} else { |
| 140 |
lx &= ~(((uint32_t)(0xffffffff)) >> (j0 - 20)); |
| 141 |
} |
| 142 |
INSERT_WORDS(x,ix,lx); |
| 143 |
|
| 144 |
ax -= x; |
| 145 |
EXTRACT_WORDS(ix, lx, ax); |
| 146 |
|
| 147 |
if (ix < 0x3fe00000) /* |x| < 0.5 */ |
| 148 |
t = ax == 0 ? 0 : __kernel_tanpi(ax); |
| 149 |
else if (ax == 0.5) |
| 150 |
return ((ax - ax) / (ax - ax)); |
| 151 |
else |
| 152 |
t = - __kernel_tanpi(1 - ax); |
| 153 |
|
| 154 |
return ((hx & 0x80000000) ? -t : t); |
| 155 |
} |
| 156 |
|
| 157 |
/* x = +-inf or nan. */ |
| 158 |
if (ix >= 0x7f800000) |
| 159 |
return (vzero / vzero); |
| 160 |
|
| 161 |
/* |
| 162 |
* |x| >= 0x1p52 is always an integer, so return +-0. |
| 163 |
* FIXME: should this raise FE_INEXACT or FE_INVALID? |
| 164 |
*/ |
| 165 |
if (ax + 1 > 1) |
| 166 |
ax = copysign(0, x); |
| 167 |
return (ax); |
| 168 |
} |
| 169 |
|
| 170 |
#if LDBL_MANT_DIG == 53 |
| 171 |
__weak_reference(tanpi, tanpil); |
| 172 |
#endif |