1//===-- Implementation header for tanpif16 ----------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TANPIF16_H
10#define LLVM_LIBC_SRC___SUPPORT_MATH_TANPIF16_H
11
12#include "include/llvm-libc-macros/float16-macros.h"
13
14#ifdef LIBC_TYPES_HAS_FLOAT16
15
16#include "hdr/errno_macros.h"
17#include "hdr/fenv_macros.h"
18#include "sincosf16_utils.h"
19#include "src/__support/FPUtil/FEnvImpl.h"
20#include "src/__support/FPUtil/FPBits.h"
21#include "src/__support/FPUtil/cast.h"
22#include "src/__support/FPUtil/except_value_utils.h"
23#include "src/__support/FPUtil/multiply_add.h"
24#include "src/__support/macros/optimization.h"
25
26namespace LIBC_NAMESPACE_DECL {
27namespace math {
28
29LIBC_INLINE float16 tanpif16(float16 x) {
30 using namespace sincosf16_internal;
31 using FPBits = typename fputil::FPBits<float16>;
32 FPBits xbits(x);
33
34 uint16_t x_u = xbits.uintval();
35 uint16_t x_abs = x_u & 0x7fff;
36
37 // Handle exceptional values
38 if (LIBC_UNLIKELY(x_abs <= 0x4335)) {
39 if (LIBC_UNLIKELY(x_abs == 0U))
40 return x;
41
42#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
43 constexpr size_t N_EXCEPTS = 21;
44
45 constexpr fputil::ExceptValues<float16, N_EXCEPTS> TANPIF16_EXCEPTS{.values: {
46 // (input, RZ output, RU offset, RD offset, RN offset)
47 {.input: 0x07f2, .rnd_towardzero_result: 0x0e3d, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0}, {.input: 0x086a, .rnd_towardzero_result: 0x0eee, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 1},
48 {.input: 0x08db, .rnd_towardzero_result: 0x0fa0, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0}, {.input: 0x094c, .rnd_towardzero_result: 0x1029, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0},
49 {.input: 0x0b10, .rnd_towardzero_result: 0x118c, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0}, {.input: 0x1ce0, .rnd_towardzero_result: 0x23a8, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 1},
50 {.input: 0x1235, .rnd_towardzero_result: 0x18e0, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0}, {.input: 0x2579, .rnd_towardzero_result: 0x2c4e, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0},
51 {.input: 0x28b2, .rnd_towardzero_result: 0x2f68, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 1}, {.input: 0x2a43, .rnd_towardzero_result: 0x30f4, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 1},
52 {.input: 0x31b7, .rnd_towardzero_result: 0x3907, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0}, {.input: 0x329d, .rnd_towardzero_result: 0x3a12, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 1},
53 {.input: 0x34f1, .rnd_towardzero_result: 0x3dd7, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0}, {.input: 0x3658, .rnd_towardzero_result: 0x41ee, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0},
54 {.input: 0x38d4, .rnd_towardzero_result: 0xc1ee, .rnd_upward_offset: 0, .rnd_downward_offset: 1, .rnd_tonearest_offset: 0}, {.input: 0x3d96, .rnd_towardzero_result: 0x41ee, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0},
55 {.input: 0x3e6a, .rnd_towardzero_result: 0xc1ee, .rnd_upward_offset: 0, .rnd_downward_offset: 1, .rnd_tonearest_offset: 0}, {.input: 0x40cb, .rnd_towardzero_result: 0x41ee, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0},
56 {.input: 0x4135, .rnd_towardzero_result: 0xc1ee, .rnd_upward_offset: 0, .rnd_downward_offset: 1, .rnd_tonearest_offset: 0}, {.input: 0x42cb, .rnd_towardzero_result: 0x41ee, .rnd_upward_offset: 1, .rnd_downward_offset: 0, .rnd_tonearest_offset: 0},
57 {.input: 0x4335, .rnd_towardzero_result: 0xc1ee, .rnd_upward_offset: 0, .rnd_downward_offset: 1, .rnd_tonearest_offset: 0},
58 }};
59
60 bool x_sign = x_u >> 15;
61
62 if (auto r = TANPIF16_EXCEPTS.lookup_odd(x_abs, sign: x_sign);
63 LIBC_UNLIKELY(r.has_value()))
64 return r.value();
65#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
66 }
67
68 // Numbers greater or equal to 2^10 are integers, or infinity, or NaN
69 if (LIBC_UNLIKELY(x_abs >= 0x6400)) {
70 // Check for NaN or infinity values
71 if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
72 if (xbits.is_signaling_nan()) {
73 fputil::raise_except_if_required(FE_INVALID);
74 return FPBits::quiet_nan().get_val();
75 }
76 // is inf
77 if (x_abs == 0x7c00) {
78 fputil::set_errno_if_required(EDOM);
79 fputil::raise_except_if_required(FE_INVALID);
80 }
81
82 return x + FPBits::quiet_nan().get_val();
83 }
84
85 return FPBits::zero(sign: xbits.sign()).get_val();
86 }
87 // Range reduction:
88 // For |x| > 1/32, we perform range reduction as follows:
89 // Find k and y such that:
90 // x = (k + y) * 1/32
91 // k is an integer
92 // |y| < 0.5
93 //
94 // This is done by performing:
95 // k = round(x * 32)
96 // y = x * 32 - k
97 //
98 // Once k and y are computed, we then deduce the answer by the formula:
99 // tan(x) = sin(x) / cos(x)
100 // = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k)
101 float xf = x;
102 float sin_k = 0, cos_k = 0, sin_y = 0, cosm1_y = 0;
103 sincospif16_eval(xf, sin_k, cos_k, sin_y, cosm1_y);
104
105 if (LIBC_UNLIKELY(sin_y == 0 && cos_k == 0)) {
106 fputil::set_errno_if_required(EDOM);
107 fputil::raise_except_if_required(FE_DIVBYZERO);
108
109 int16_t x_mp5_u = static_cast<int16_t>(x - 0.5);
110 return ((x_mp5_u & 0x1) ? -1 : 1) * FPBits::inf().get_val();
111 }
112
113 using fputil::multiply_add;
114 return fputil::cast<float16>(
115 x: multiply_add(x: sin_y, y: cos_k, z: multiply_add(x: cosm1_y, y: sin_k, z: sin_k)) /
116 multiply_add(x: sin_y, y: -sin_k, z: multiply_add(x: cosm1_y, y: cos_k, z: cos_k)));
117}
118
119} // namespace math
120} // namespace LIBC_NAMESPACE_DECL
121
122#endif // LIBC_TYPES_HAS_FLOAT16
123
124#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TANPIF16_H
125