xref: /aosp_15_r20/external/llvm-libc/src/math/generic/sincosf_utils.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1*71db0c75SAndroid Build Coastguard Worker //===-- Collection of utils for sinf/cosf/sincosf ---------------*- C++ -*-===//
2*71db0c75SAndroid Build Coastguard Worker //
3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*71db0c75SAndroid Build Coastguard Worker //
7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*71db0c75SAndroid Build Coastguard Worker 
9*71db0c75SAndroid Build Coastguard Worker #ifndef LLVM_LIBC_SRC_MATH_GENERIC_SINCOSF_UTILS_H
10*71db0c75SAndroid Build Coastguard Worker #define LLVM_LIBC_SRC_MATH_GENERIC_SINCOSF_UTILS_H
11*71db0c75SAndroid Build Coastguard Worker 
12*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/FPBits.h"
13*71db0c75SAndroid Build Coastguard Worker #include "src/__support/FPUtil/PolyEval.h"
14*71db0c75SAndroid Build Coastguard Worker #include "src/__support/macros/config.h"
15*71db0c75SAndroid Build Coastguard Worker #include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA
16*71db0c75SAndroid Build Coastguard Worker 
17*71db0c75SAndroid Build Coastguard Worker #if defined(LIBC_TARGET_CPU_HAS_FMA)
18*71db0c75SAndroid Build Coastguard Worker #include "range_reduction_fma.h"
19*71db0c75SAndroid Build Coastguard Worker // using namespace LIBC_NAMESPACE::fma;
20*71db0c75SAndroid Build Coastguard Worker using LIBC_NAMESPACE::fma::FAST_PASS_BOUND;
21*71db0c75SAndroid Build Coastguard Worker using LIBC_NAMESPACE::fma::large_range_reduction;
22*71db0c75SAndroid Build Coastguard Worker using LIBC_NAMESPACE::fma::small_range_reduction;
23*71db0c75SAndroid Build Coastguard Worker 
24*71db0c75SAndroid Build Coastguard Worker #else
25*71db0c75SAndroid Build Coastguard Worker #include "range_reduction.h"
26*71db0c75SAndroid Build Coastguard Worker // using namespace LIBC_NAMESPACE::generic;
27*71db0c75SAndroid Build Coastguard Worker using LIBC_NAMESPACE::generic::FAST_PASS_BOUND;
28*71db0c75SAndroid Build Coastguard Worker using LIBC_NAMESPACE::generic::large_range_reduction;
29*71db0c75SAndroid Build Coastguard Worker using LIBC_NAMESPACE::generic::small_range_reduction;
30*71db0c75SAndroid Build Coastguard Worker #endif // LIBC_TARGET_CPU_HAS_FMA
31*71db0c75SAndroid Build Coastguard Worker 
32*71db0c75SAndroid Build Coastguard Worker namespace LIBC_NAMESPACE_DECL {
33*71db0c75SAndroid Build Coastguard Worker 
34*71db0c75SAndroid Build Coastguard Worker // Lookup table for sin(k * pi / 32) with k = 0, ..., 63.
35*71db0c75SAndroid Build Coastguard Worker // Table is generated with Sollya as follow:
36*71db0c75SAndroid Build Coastguard Worker // > display = hexadecimal;
37*71db0c75SAndroid Build Coastguard Worker // > for k from 0 to 63 do { D(sin(k * pi/32)); };
38*71db0c75SAndroid Build Coastguard Worker const double SIN_K_PI_OVER_32[64] = {
39*71db0c75SAndroid Build Coastguard Worker     0x0.0000000000000p+0,  0x1.917a6bc29b42cp-4,  0x1.8f8b83c69a60bp-3,
40*71db0c75SAndroid Build Coastguard Worker     0x1.294062ed59f06p-2,  0x1.87de2a6aea963p-2,  0x1.e2b5d3806f63bp-2,
41*71db0c75SAndroid Build Coastguard Worker     0x1.1c73b39ae68c8p-1,  0x1.44cf325091dd6p-1,  0x1.6a09e667f3bcdp-1,
42*71db0c75SAndroid Build Coastguard Worker     0x1.8bc806b151741p-1,  0x1.a9b66290ea1a3p-1,  0x1.c38b2f180bdb1p-1,
43*71db0c75SAndroid Build Coastguard Worker     0x1.d906bcf328d46p-1,  0x1.e9f4156c62ddap-1,  0x1.f6297cff75cbp-1,
44*71db0c75SAndroid Build Coastguard Worker     0x1.fd88da3d12526p-1,  0x1.0000000000000p+0,  0x1.fd88da3d12526p-1,
45*71db0c75SAndroid Build Coastguard Worker     0x1.f6297cff75cbp-1,   0x1.e9f4156c62ddap-1,  0x1.d906bcf328d46p-1,
46*71db0c75SAndroid Build Coastguard Worker     0x1.c38b2f180bdb1p-1,  0x1.a9b66290ea1a3p-1,  0x1.8bc806b151741p-1,
47*71db0c75SAndroid Build Coastguard Worker     0x1.6a09e667f3bcdp-1,  0x1.44cf325091dd6p-1,  0x1.1c73b39ae68c8p-1,
48*71db0c75SAndroid Build Coastguard Worker     0x1.e2b5d3806f63bp-2,  0x1.87de2a6aea963p-2,  0x1.294062ed59f06p-2,
49*71db0c75SAndroid Build Coastguard Worker     0x1.8f8b83c69a60bp-3,  0x1.917a6bc29b42cp-4,  0x0.0000000000000p+0,
50*71db0c75SAndroid Build Coastguard Worker     -0x1.917a6bc29b42cp-4, -0x1.8f8b83c69a60bp-3, -0x1.294062ed59f06p-2,
51*71db0c75SAndroid Build Coastguard Worker     -0x1.87de2a6aea963p-2, -0x1.e2b5d3806f63bp-2, -0x1.1c73b39ae68c8p-1,
52*71db0c75SAndroid Build Coastguard Worker     -0x1.44cf325091dd6p-1, -0x1.6a09e667f3bcdp-1, -0x1.8bc806b151741p-1,
53*71db0c75SAndroid Build Coastguard Worker     -0x1.a9b66290ea1a3p-1, -0x1.c38b2f180bdb1p-1, -0x1.d906bcf328d46p-1,
54*71db0c75SAndroid Build Coastguard Worker     -0x1.e9f4156c62ddap-1, -0x1.f6297cff75cbp-1,  -0x1.fd88da3d12526p-1,
55*71db0c75SAndroid Build Coastguard Worker     -0x1.0000000000000p+0, -0x1.fd88da3d12526p-1, -0x1.f6297cff75cbp-1,
56*71db0c75SAndroid Build Coastguard Worker     -0x1.e9f4156c62ddap-1, -0x1.d906bcf328d46p-1, -0x1.c38b2f180bdb1p-1,
57*71db0c75SAndroid Build Coastguard Worker     -0x1.a9b66290ea1a3p-1, -0x1.8bc806b151741p-1, -0x1.6a09e667f3bcdp-1,
58*71db0c75SAndroid Build Coastguard Worker     -0x1.44cf325091dd6p-1, -0x1.1c73b39ae68c8p-1, -0x1.e2b5d3806f63bp-2,
59*71db0c75SAndroid Build Coastguard Worker     -0x1.87de2a6aea963p-2, -0x1.294062ed59f06p-2, -0x1.8f8b83c69a60bp-3,
60*71db0c75SAndroid Build Coastguard Worker     -0x1.917a6bc29b42cp-4,
61*71db0c75SAndroid Build Coastguard Worker };
62*71db0c75SAndroid Build Coastguard Worker 
sincosf_poly_eval(int64_t k,double y,double & sin_k,double & cos_k,double & sin_y,double & cosm1_y)63*71db0c75SAndroid Build Coastguard Worker static LIBC_INLINE void sincosf_poly_eval(int64_t k, double y, double &sin_k,
64*71db0c75SAndroid Build Coastguard Worker                                           double &cos_k, double &sin_y,
65*71db0c75SAndroid Build Coastguard Worker                                           double &cosm1_y) {
66*71db0c75SAndroid Build Coastguard Worker   // After range reduction, k = round(x * 32 / pi) and y = (x * 32 / pi) - k.
67*71db0c75SAndroid Build Coastguard Worker   // So k is an integer and -0.5 <= y <= 0.5.
68*71db0c75SAndroid Build Coastguard Worker   // Then sin(x) = sin((k + y)*pi/32)
69*71db0c75SAndroid Build Coastguard Worker   //             = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32)
70*71db0c75SAndroid Build Coastguard Worker 
71*71db0c75SAndroid Build Coastguard Worker   sin_k = SIN_K_PI_OVER_32[k & 63];
72*71db0c75SAndroid Build Coastguard Worker   // cos(k * pi/32) = sin(k * pi/32 + pi/2) = sin((k + 16) * pi/32).
73*71db0c75SAndroid Build Coastguard Worker   // cos_k = cos(k * pi/32)
74*71db0c75SAndroid Build Coastguard Worker   cos_k = SIN_K_PI_OVER_32[(k + 16) & 63];
75*71db0c75SAndroid Build Coastguard Worker 
76*71db0c75SAndroid Build Coastguard Worker   double ysq = y * y;
77*71db0c75SAndroid Build Coastguard Worker 
78*71db0c75SAndroid Build Coastguard Worker   // Degree-6 minimax even polynomial for sin(y*pi/32)/y generated by Sollya
79*71db0c75SAndroid Build Coastguard Worker   // with:
80*71db0c75SAndroid Build Coastguard Worker   // > Q = fpminimax(sin(y*pi/32)/y, [|0, 2, 4, 6|], [|D...|], [0, 0.5]);
81*71db0c75SAndroid Build Coastguard Worker   sin_y =
82*71db0c75SAndroid Build Coastguard Worker       y * fputil::polyeval(ysq, 0x1.921fb54442d18p-4, -0x1.4abbce625abb1p-13,
83*71db0c75SAndroid Build Coastguard Worker                            0x1.466bc624f2776p-24, -0x1.32c3a619d4a7ep-36);
84*71db0c75SAndroid Build Coastguard Worker   // Degree-6 minimax even polynomial for cos(y*pi/32) generated by Sollya with:
85*71db0c75SAndroid Build Coastguard Worker   // > P = fpminimax(cos(x*pi/32), [|0, 2, 4, 6|], [|1, D...|], [0, 0.5]);
86*71db0c75SAndroid Build Coastguard Worker   // Note that cosm1_y = cos(y*pi/32) - 1.
87*71db0c75SAndroid Build Coastguard Worker   cosm1_y = ysq * fputil::polyeval(ysq, -0x1.3bd3cc9be430bp-8,
88*71db0c75SAndroid Build Coastguard Worker                                    0x1.03c1f070c2e27p-18, -0x1.55cc84bd942p-30);
89*71db0c75SAndroid Build Coastguard Worker }
90*71db0c75SAndroid Build Coastguard Worker 
sincosf_eval(double xd,uint32_t x_abs,double & sin_k,double & cos_k,double & sin_y,double & cosm1_y)91*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE void sincosf_eval(double xd, uint32_t x_abs, double &sin_k,
92*71db0c75SAndroid Build Coastguard Worker                               double &cos_k, double &sin_y, double &cosm1_y) {
93*71db0c75SAndroid Build Coastguard Worker   int64_t k;
94*71db0c75SAndroid Build Coastguard Worker   double y;
95*71db0c75SAndroid Build Coastguard Worker 
96*71db0c75SAndroid Build Coastguard Worker   if (LIBC_LIKELY(x_abs < FAST_PASS_BOUND)) {
97*71db0c75SAndroid Build Coastguard Worker     k = small_range_reduction(xd, y);
98*71db0c75SAndroid Build Coastguard Worker   } else {
99*71db0c75SAndroid Build Coastguard Worker     fputil::FPBits<float> x_bits(x_abs);
100*71db0c75SAndroid Build Coastguard Worker     k = large_range_reduction(xd, x_bits.get_exponent(), y);
101*71db0c75SAndroid Build Coastguard Worker   }
102*71db0c75SAndroid Build Coastguard Worker 
103*71db0c75SAndroid Build Coastguard Worker   sincosf_poly_eval(k, y, sin_k, cos_k, sin_y, cosm1_y);
104*71db0c75SAndroid Build Coastguard Worker }
105*71db0c75SAndroid Build Coastguard Worker 
106*71db0c75SAndroid Build Coastguard Worker // Return k and y, where
107*71db0c75SAndroid Build Coastguard Worker //   k = round(x * 32) and y = (x * 32) - k.
108*71db0c75SAndroid Build Coastguard Worker //   => pi * x = (k + y) * pi / 32
range_reduction_sincospi(double x,double & y)109*71db0c75SAndroid Build Coastguard Worker static LIBC_INLINE int64_t range_reduction_sincospi(double x, double &y) {
110*71db0c75SAndroid Build Coastguard Worker   double kd = fputil::nearest_integer(x * 32);
111*71db0c75SAndroid Build Coastguard Worker   y = fputil::multiply_add<double>(x, 32.0, -kd);
112*71db0c75SAndroid Build Coastguard Worker 
113*71db0c75SAndroid Build Coastguard Worker   return static_cast<int64_t>(kd);
114*71db0c75SAndroid Build Coastguard Worker }
115*71db0c75SAndroid Build Coastguard Worker 
sincospif_eval(double xd,double & sin_k,double & cos_k,double & sin_y,double & cosm1_y)116*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE void sincospif_eval(double xd, double &sin_k, double &cos_k,
117*71db0c75SAndroid Build Coastguard Worker                                 double &sin_y, double &cosm1_y) {
118*71db0c75SAndroid Build Coastguard Worker   double y;
119*71db0c75SAndroid Build Coastguard Worker   int64_t k = range_reduction_sincospi(xd, y);
120*71db0c75SAndroid Build Coastguard Worker   sincosf_poly_eval(k, y, sin_k, cos_k, sin_y, cosm1_y);
121*71db0c75SAndroid Build Coastguard Worker }
122*71db0c75SAndroid Build Coastguard Worker 
123*71db0c75SAndroid Build Coastguard Worker } // namespace LIBC_NAMESPACE_DECL
124*71db0c75SAndroid Build Coastguard Worker 
125*71db0c75SAndroid Build Coastguard Worker #endif // LLVM_LIBC_SRC_MATH_GENERIC_SINCOSF_UTILS_H
126