]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/ieee754/ldbl-128ibm/k_sincosl.c
Fix sin, sincos missing underflows (bug 16526, bug 16538).
[thirdparty/glibc.git] / sysdeps / ieee754 / ldbl-128ibm / k_sincosl.c
CommitLineData
f964490f 1/* Quad-precision floating point sine and cosine on <-pi/4,pi/4>.
b168057a 2 Copyright (C) 1999-2015 Free Software Foundation, Inc.
f964490f
RM
3 This file is part of the GNU C Library.
4 Contributed by Jakub Jelinek <jj@ultra.linux.cz>
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
17 License along with the GNU C Library; if not, see
18 <http://www.gnu.org/licenses/>. */
f964490f 19
ad39cce0 20#include <float.h>
1ed0291c
RH
21#include <math.h>
22#include <math_private.h>
f964490f
RM
23
24static const long double c[] = {
25#define ONE c[0]
26 1.00000000000000000000000000000000000E+00L, /* 3fff0000000000000000000000000000 */
27
28/* cos x ~ ONE + x^2 ( SCOS1 + SCOS2 * x^2 + ... + SCOS4 * x^6 + SCOS5 * x^8 )
29 x in <0,1/256> */
30#define SCOS1 c[1]
31#define SCOS2 c[2]
32#define SCOS3 c[3]
33#define SCOS4 c[4]
34#define SCOS5 c[5]
35-5.00000000000000000000000000000000000E-01L, /* bffe0000000000000000000000000000 */
36 4.16666666666666666666666666556146073E-02L, /* 3ffa5555555555555555555555395023 */
37-1.38888888888888888888309442601939728E-03L, /* bff56c16c16c16c16c16a566e42c0375 */
38 2.48015873015862382987049502531095061E-05L, /* 3fefa01a01a019ee02dcf7da2d6d5444 */
39-2.75573112601362126593516899592158083E-07L, /* bfe927e4f5dce637cb0b54908754bde0 */
40
41/* cos x ~ ONE + x^2 ( COS1 + COS2 * x^2 + ... + COS7 * x^12 + COS8 * x^14 )
42 x in <0,0.1484375> */
43#define COS1 c[6]
44#define COS2 c[7]
45#define COS3 c[8]
46#define COS4 c[9]
47#define COS5 c[10]
48#define COS6 c[11]
49#define COS7 c[12]
50#define COS8 c[13]
51-4.99999999999999999999999999999999759E-01L, /* bffdfffffffffffffffffffffffffffb */
52 4.16666666666666666666666666651287795E-02L, /* 3ffa5555555555555555555555516f30 */
53-1.38888888888888888888888742314300284E-03L, /* bff56c16c16c16c16c16c16a463dfd0d */
54 2.48015873015873015867694002851118210E-05L, /* 3fefa01a01a01a01a0195cebe6f3d3a5 */
55-2.75573192239858811636614709689300351E-07L, /* bfe927e4fb7789f5aa8142a22044b51f */
56 2.08767569877762248667431926878073669E-09L, /* 3fe21eed8eff881d1e9262d7adff4373 */
57-1.14707451049343817400420280514614892E-11L, /* bfda9397496922a9601ed3d4ca48944b */
58 4.77810092804389587579843296923533297E-14L, /* 3fd2ae5f8197cbcdcaf7c3fb4523414c */
59
60/* sin x ~ ONE * x + x^3 ( SSIN1 + SSIN2 * x^2 + ... + SSIN4 * x^6 + SSIN5 * x^8 )
61 x in <0,1/256> */
62#define SSIN1 c[14]
63#define SSIN2 c[15]
64#define SSIN3 c[16]
65#define SSIN4 c[17]
66#define SSIN5 c[18]
67-1.66666666666666666666666666666666659E-01L, /* bffc5555555555555555555555555555 */
68 8.33333333333333333333333333146298442E-03L, /* 3ff81111111111111111111110fe195d */
69-1.98412698412698412697726277416810661E-04L, /* bff2a01a01a01a01a019e7121e080d88 */
70 2.75573192239848624174178393552189149E-06L, /* 3fec71de3a556c640c6aaa51aa02ab41 */
71-2.50521016467996193495359189395805639E-08L, /* bfe5ae644ee90c47dc71839de75b2787 */
72
73/* sin x ~ ONE * x + x^3 ( SIN1 + SIN2 * x^2 + ... + SIN7 * x^12 + SIN8 * x^14 )
74 x in <0,0.1484375> */
75#define SIN1 c[19]
76#define SIN2 c[20]
77#define SIN3 c[21]
78#define SIN4 c[22]
79#define SIN5 c[23]
80#define SIN6 c[24]
81#define SIN7 c[25]
82#define SIN8 c[26]
83-1.66666666666666666666666666666666538e-01L, /* bffc5555555555555555555555555550 */
84 8.33333333333333333333333333307532934e-03L, /* 3ff811111111111111111111110e7340 */
85-1.98412698412698412698412534478712057e-04L, /* bff2a01a01a01a01a01a019e7a626296 */
86 2.75573192239858906520896496653095890e-06L, /* 3fec71de3a556c7338fa38527474b8f5 */
87-2.50521083854417116999224301266655662e-08L, /* bfe5ae64567f544e16c7de65c2ea551f */
88 1.60590438367608957516841576404938118e-10L, /* 3fde6124613a811480538a9a41957115 */
89-7.64716343504264506714019494041582610e-13L, /* bfd6ae7f3d5aef30c7bc660b060ef365 */
90 2.81068754939739570236322404393398135e-15L, /* 3fce9510115aabf87aceb2022a9a9180 */
91};
92
93#define SINCOSL_COS_HI 0
94#define SINCOSL_COS_LO 1
95#define SINCOSL_SIN_HI 2
96#define SINCOSL_SIN_LO 3
97extern const long double __sincosl_table[];
98
99void
100__kernel_sincosl(long double x, long double y, long double *sinx, long double *cosx, int iy)
101{
102 long double h, l, z, sin_l, cos_l_m1;
103 int64_t ix;
4ebd120c
AM
104 uint32_t tix, hix, index;
105 double xhi, hhi;
106
107 xhi = ldbl_high (x);
108 EXTRACT_WORDS64 (ix, xhi);
109 tix = ((uint64_t)ix) >> 32;
f964490f
RM
110 tix &= ~0x80000000; /* tix = |x|'s high 32 bits */
111 if (tix < 0x3fc30000) /* |x| < 0.1484375 */
112 {
113 /* Argument is small enough to approximate it by a Chebyshev
114 polynomial of degree 16(17). */
115 if (tix < 0x3c600000) /* |x| < 2^-57 */
ad39cce0
JM
116 {
117 if (fabsl (x) < LDBL_MIN)
118 {
119 long double force_underflow = x * x;
120 math_force_eval (force_underflow);
121 }
122 if (!((int)x)) /* generate inexact */
123 {
124 *sinx = x;
125 *cosx = ONE;
126 return;
127 }
128 }
f964490f
RM
129 z = x * x;
130 *sinx = x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+
131 z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8)))))))));
132 *cosx = ONE + (z*(COS1+z*(COS2+z*(COS3+z*(COS4+
133 z*(COS5+z*(COS6+z*(COS7+z*COS8))))))));
134 }
135 else
136 {
137 /* So that we don't have to use too large polynomial, we find
138 l and h such that x = l + h, where fabsl(l) <= 1.0/256 with 83
139 possible values for h. We look up cosl(h) and sinl(h) in
140 pre-computed tables, compute cosl(l) and sinl(l) using a
141 Chebyshev polynomial of degree 10(11) and compute
142 sinl(h+l) = sinl(h)cosl(l) + cosl(h)sinl(l) and
143 cosl(h+l) = cosl(h)cosl(l) - sinl(h)sinl(l). */
16f0eced
RM
144 int six = tix;
145 tix = ((six - 0x3ff00000) >> 4) + 0x3fff0000;
146 index = 0x3ffe - (tix >> 16);
147 hix = (tix + (0x200 << index)) & (0xfffffc00 << index);
148 x = fabsl (x);
149 switch (index)
150 {
151 case 0: index = ((45 << 10) + hix - 0x3ffe0000) >> 8; break;
152 case 1: index = ((13 << 11) + hix - 0x3ffd0000) >> 9; break;
153 default:
154 case 2: index = (hix - 0x3ffc3000) >> 10; break;
155 }
156 hix = (hix << 4) & 0x3fffffff;
157/*
158 The following should work for double but generates the wrong index.
159 For now the code above converts double to ieee extended to compute
9c84384c
JM
160 the index back to double for the h value.
161
16f0eced 162
f964490f
RM
163 index = 0x3fe - (tix >> 20);
164 hix = (tix + (0x2000 << index)) & (0xffffc000 << index);
c0df8e69
JM
165 if (signbit (x))
166 {
167 x = -x;
168 y = -y;
169 }
f964490f
RM
170 switch (index)
171 {
172 case 0: index = ((45 << 14) + hix - 0x3fe00000) >> 12; break;
173 case 1: index = ((13 << 15) + hix - 0x3fd00000) >> 13; break;
174 default:
175 case 2: index = (hix - 0x3fc30000) >> 14; break;
176 }
16f0eced 177*/
4ebd120c
AM
178 INSERT_WORDS64 (hhi, ((uint64_t)hix) << 32);
179 h = hhi;
f964490f
RM
180 if (iy)
181 l = y - (h - x);
182 else
183 l = x - h;
184 z = l * l;
185 sin_l = l*(ONE+z*(SSIN1+z*(SSIN2+z*(SSIN3+z*(SSIN4+z*SSIN5)))));
186 cos_l_m1 = z*(SCOS1+z*(SCOS2+z*(SCOS3+z*(SCOS4+z*SCOS5))));
187 z = __sincosl_table [index + SINCOSL_SIN_HI]
188 + (__sincosl_table [index + SINCOSL_SIN_LO]
189 + (__sincosl_table [index + SINCOSL_SIN_HI] * cos_l_m1)
190 + (__sincosl_table [index + SINCOSL_COS_HI] * sin_l));
191 *sinx = (ix < 0) ? -z : z;
192 *cosx = __sincosl_table [index + SINCOSL_COS_HI]
193 + (__sincosl_table [index + SINCOSL_COS_LO]
194 - (__sincosl_table [index + SINCOSL_SIN_HI] * sin_l
195 - __sincosl_table [index + SINCOSL_COS_HI] * cos_l_m1));
196 }
197}