77// ===----------------------------------------------------------------------===//
88
99#include " src/math/sinpif16.h"
10+ #include " sincosf16_utils.h"
1011#include " src/__support/FPUtil/FEnvImpl.h"
1112#include " src/__support/FPUtil/FPBits.h"
12- #include " src/__support/FPUtil/PolyEval.h"
1313#include " src/__support/FPUtil/cast.h"
1414#include " src/__support/FPUtil/multiply_add.h"
15- #include " src/__support/FPUtil/nearest_integer.h"
16- #include " src/__support/common.h"
17- #include " src/__support/macros/config.h"
1815
1916namespace LIBC_NAMESPACE_DECL {
20-
21- // Lookup table for sin(k * pi / 32) with k = 0, ..., 63.
22- // Table is generated with Sollya as follows:
23- // > display = hexadecimmal;
24- // > for k from 0 to 63 do { round(sin(k * pi/32), SG, RN); };
25- static constexpr float SIN_K_PI_OVER_32[64 ] = {
26- 0x0 .0p0, 0x1 .917a6cp-4 , 0x1 .8f8b84p-3 , 0x1 .294062p-2 ,
27- 0x1 .87de2ap-2 , 0x1 .e2b5d4p -2 , 0x1 .1c73b4p-1 , 0x1 .44cf32p-1 ,
28- 0x1 .6a09e6p-1 , 0x1 .8bc806p-1 , 0x1 .a9b662p -1 , 0x1 .c38b3p -1 ,
29- 0x1 .d906bcp -1 , 0x1 .e9f416p -1 , 0x1 .f6297cp -1 , 0x1 .fd88dap -1 ,
30- 0x1p0, 0x1 .fd88dap -1 , 0x1 .f6297cp -1 , 0x1 .e9f416p -1 ,
31- 0x1 .d906bcp -1 , 0x1 .c38b3p -1 , 0x1 .a9b662p -1 , 0x1 .8bc806p-1 ,
32- 0x1 .6a09e6p-1 , 0x1 .44cf32p-1 , 0x1 .1c73b4p-1 , 0x1 .e2b5d4p -2 ,
33- 0x1 .87de2ap-2 , 0x1 .294062p-2 , 0x1 .8f8b84p-3 , 0x1 .917a6cp-4 ,
34- 0x0 .0p0, -0x1 .917a6cp-4 , -0x1 .8f8b84p-3 , -0x1 .294062p-2 ,
35- -0x1 .87de2ap-2 , -0x1 .e2b5d4p -2 , -0x1 .1c73b4p-1 , -0x1 .44cf32p-1 ,
36- -0x1 .6a09e6p-1 , -0x1 .8bc806p-1 , -0x1 .a9b662p -1 , -0x1 .c38b3p -1 ,
37- -0x1 .d906bcp -1 , -0x1 .e9f416p -1 , -0x1 .f6297ep -1 , -0x1 .fd88dap -1 ,
38- -0x1p0, -0x1 .fd88dap -1 , -0x1 .f6297cp -1 , -0x1 .e9f416p -1 ,
39- -0x1 .d906bcp -1 , -0x1 .c38b3p -1 , -0x1 .a9b662p -1 , -0x1 .8bc806p-1 ,
40- -0x1 .6a09e6p-1 , -0x1 .44cf32p-1 , -0x1 .1c73b4p-1 , -0x1 .e2b5d4p -2 ,
41- -0x1 .87de2ap-2 , -0x1 .294062p-2 , -0x1 .8f8b84p-3 , -0x1 .917a6cp-4 };
42-
43- static LIBC_INLINE int32_t range_reduction (float x, float &y) {
44- float kf = fputil::nearest_integer (x * 32 );
45- y = fputil::multiply_add<float >(x, 32.0 , -kf);
46-
47- return static_cast <int32_t >(kf);
48- }
49-
5017LLVM_LIBC_FUNCTION (float16, sinpif16, (float16 x)) {
5118 using FPBits = typename fputil::FPBits<float16>;
5219 FPBits xbits (x);
5320
5421 uint16_t x_u = xbits.uintval ();
5522 uint16_t x_abs = x_u & 0x7fff ;
23+ float xf = x;
5624
5725 // Range reduction:
5826 // For |x| > 1/32, we perform range reduction as follows:
@@ -68,8 +36,8 @@ LLVM_LIBC_FUNCTION(float16, sinpif16, (float16 x)) {
6836 // Once k and y are computed, we then deduce the answer by the sine of sum
6937 // formula:
7038 // sin(x * pi) = sin((k + y) * pi/32)
71- // = sin(k * pi/32) * cos(y * pi/32) + sin (y * pi/32) * cos (k *
72- // pi/32)
39+ // = sin(k * pi/32) * cos(y * pi/32)
40+ // + sin (y * pi/32) * cos (k * pi/32)
7341 // The values of sin(k * pi/32) and cos (k * pi/32) for k = 0...63 are
7442 // precomputed and stored using a vector of 64 single precision floats. sin(y
7543 // * pi/32) and cos(y * pi/32) are computed using degree-9 chebyshev
@@ -94,36 +62,8 @@ LLVM_LIBC_FUNCTION(float16, sinpif16, (float16 x)) {
9462 return FPBits::zero (xbits.sign ()).get_val ();
9563 }
9664
97- float f32 = x;
98- float y;
99- int32_t k = range_reduction (f32 , y);
100-
101- float sin_k = SIN_K_PI_OVER_32[k & 63 ];
102- float cos_k = SIN_K_PI_OVER_32[(k + 16 ) & 63 ];
103-
104- // Recall;
105- // sin(x * pi/32) = sin((k + y) * pi/32)
106- // = sin(y * pi/32) * cos(k * pi/32) + cos(y * pi/32) * sin(k *
107- // pi/32) Recall, after range reduction, -0.5 <= y <= 0.5. For very small
108- // values of y, calculating sin(y * p/32) can be inaccurate. Generating a
109- // polynomial for sin(y * p/32)/y instead significantly reduces the relative
110- // errors.
111- float ysq = y * y;
112-
113- // Degree-6 minimax even polynomial for sin(y*pi/32)/y generated by Sollya
114- // with: > Q = fpminimax(sin(y*pi/32)/y, [|0, 2, 4, 6|], [|SG...|], [0, 0.5]);
115- float sin_y = y * fputil::polyeval (ysq, 0x1 .921fb6p-4f , -0x1 .4aeabcp-13f ,
116- 0x1 .a03354p -21f , -0x1 .ad02d2p -20f );
117-
118- // Note that cosm1_y = cos(y*pi/32) - 1 = cos_y - 1
119- // Derivation:
120- // sin(x * pi) = sin((k + y) * pi/32)
121- // = sin_y * cos_k + cos_y * sin_k
122- // = cos_k * sin_y + sin_k * (1 + cos_y - 1)
123- // Degree-6 minimax even polynomial for cos(y*pi/32) generated by Sollya with:
124- // > P = fpminimax(cos(y*pi/32), [|0, 2, 4, 6|],[|1, SG...|], [0, 0.5]);
125- float cosm1_y = ysq * fputil::polyeval (ysq, -0x1 .3bd3ccp-8f , 0x1 .03a61ap-18f ,
126- 0x1 .a6f7a2p -29f );
65+ float sin_k, cos_k, sin_y, cosm1_y;
66+ sincospif16_eval (xf, sin_k, cos_k, sin_y, cosm1_y);
12767
12868 if (LIBC_UNLIKELY (sin_y == 0 && sin_k == 0 ))
12969 return FPBits::zero (xbits.sign ()).get_val ();
0 commit comments