#ifndef LIBC_SRC___SUPPORT_MATH_SINCOSF_UTILS_H
#define LIBC_SRC___SUPPORT_MATH_SINCOSF_UTILS_H
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/PolyEval.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/cpu_features.h"
#if defined(LIBC_TARGET_CPU_HAS_FMA_DOUBLE)
#include "range_reduction_fma.h"
using LIBC_NAMESPACE::fma::FAST_PASS_BOUND;
using LIBC_NAMESPACE::fma::large_range_reduction;
using LIBC_NAMESPACE::fma::small_range_reduction;
#else
#include "range_reduction.h"
using LIBC_NAMESPACE::generic::FAST_PASS_BOUND;
using LIBC_NAMESPACE::generic::large_range_reduction;
using LIBC_NAMESPACE::generic::small_range_reduction;
#endif
namespace LIBC_NAMESPACE_DECL {
const double SIN_K_PI_OVER_32[64] = {
0x0.0000000000000p+0, 0x1.917a6bc29b42cp-4, 0x1.8f8b83c69a60bp-3,
0x1.294062ed59f06p-2, 0x1.87de2a6aea963p-2, 0x1.e2b5d3806f63bp-2,
0x1.1c73b39ae68c8p-1, 0x1.44cf325091dd6p-1, 0x1.6a09e667f3bcdp-1,
0x1.8bc806b151741p-1, 0x1.a9b66290ea1a3p-1, 0x1.c38b2f180bdb1p-1,
0x1.d906bcf328d46p-1, 0x1.e9f4156c62ddap-1, 0x1.f6297cff75cbp-1,
0x1.fd88da3d12526p-1, 0x1.0000000000000p+0, 0x1.fd88da3d12526p-1,
0x1.f6297cff75cbp-1, 0x1.e9f4156c62ddap-1, 0x1.d906bcf328d46p-1,
0x1.c38b2f180bdb1p-1, 0x1.a9b66290ea1a3p-1, 0x1.8bc806b151741p-1,
0x1.6a09e667f3bcdp-1, 0x1.44cf325091dd6p-1, 0x1.1c73b39ae68c8p-1,
0x1.e2b5d3806f63bp-2, 0x1.87de2a6aea963p-2, 0x1.294062ed59f06p-2,
0x1.8f8b83c69a60bp-3, 0x1.917a6bc29b42cp-4, 0x0.0000000000000p+0,
-0x1.917a6bc29b42cp-4, -0x1.8f8b83c69a60bp-3, -0x1.294062ed59f06p-2,
-0x1.87de2a6aea963p-2, -0x1.e2b5d3806f63bp-2, -0x1.1c73b39ae68c8p-1,
-0x1.44cf325091dd6p-1, -0x1.6a09e667f3bcdp-1, -0x1.8bc806b151741p-1,
-0x1.a9b66290ea1a3p-1, -0x1.c38b2f180bdb1p-1, -0x1.d906bcf328d46p-1,
-0x1.e9f4156c62ddap-1, -0x1.f6297cff75cbp-1, -0x1.fd88da3d12526p-1,
-0x1.0000000000000p+0, -0x1.fd88da3d12526p-1, -0x1.f6297cff75cbp-1,
-0x1.e9f4156c62ddap-1, -0x1.d906bcf328d46p-1, -0x1.c38b2f180bdb1p-1,
-0x1.a9b66290ea1a3p-1, -0x1.8bc806b151741p-1, -0x1.6a09e667f3bcdp-1,
-0x1.44cf325091dd6p-1, -0x1.1c73b39ae68c8p-1, -0x1.e2b5d3806f63bp-2,
-0x1.87de2a6aea963p-2, -0x1.294062ed59f06p-2, -0x1.8f8b83c69a60bp-3,
-0x1.917a6bc29b42cp-4,
};
static LIBC_INLINE void sincosf_poly_eval(int64_t k, double y, double &sin_k,
double &cos_k, double &sin_y,
double &cosm1_y) {
sin_k = SIN_K_PI_OVER_32[k & 63];
cos_k = SIN_K_PI_OVER_32[(k + 16) & 63];
double ysq = y * y;
sin_y =
y * fputil::polyeval(ysq, 0x1.921fb54442d18p-4, -0x1.4abbce625abb1p-13,
0x1.466bc624f2776p-24, -0x1.32c3a619d4a7ep-36);
cosm1_y = ysq * fputil::polyeval(ysq, -0x1.3bd3cc9be430bp-8,
0x1.03c1f070c2e27p-18, -0x1.55cc84bd942p-30);
}
LIBC_INLINE void sincosf_eval(double xd, uint32_t x_abs, double &sin_k,
double &cos_k, double &sin_y, double &cosm1_y) {
int64_t k;
double y;
if (LIBC_LIKELY(x_abs < FAST_PASS_BOUND)) {
k = small_range_reduction(xd, y);
} else {
fputil::FPBits<float> x_bits(x_abs);
k = large_range_reduction(xd, x_bits.get_exponent(), y);
}
sincosf_poly_eval(k, y, sin_k, cos_k, sin_y, cosm1_y);
}
static LIBC_INLINE int64_t range_reduction_sincospi(double x, double &y) {
double kd = fputil::nearest_integer(x * 32);
y = fputil::multiply_add(x, 32.0, -kd);
return static_cast<int64_t>(kd);
}
LIBC_INLINE void sincospif_eval(double xd, double &sin_k, double &cos_k,
double &sin_y, double &cosm1_y) {
double y;
int64_t k = range_reduction_sincospi(xd, y);
sincosf_poly_eval(k, y, sin_k, cos_k, sin_y, cosm1_y);
}
}
#endif