Skip to content

Commit c488eb0

Browse files
committed
Add tanf16 function
1 parent 1fa0302 commit c488eb0

File tree

13 files changed

+263
-5
lines changed

13 files changed

+263
-5
lines changed

libc/config/linux/x86_64/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
718718
libc.src.math.sinhf16
719719
libc.src.math.sinpif16
720720
libc.src.math.sqrtf16
721+
libc.src.math.tanf16
721722
libc.src.math.tanhf16
722723
libc.src.math.tanpif16
723724
libc.src.math.totalorderf16

libc/include/math.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,6 +2417,13 @@ functions:
24172417
return_type: float
24182418
arguments:
24192419
- type: float
2420+
- name: tanf16
2421+
standards:
2422+
- stdc
2423+
return_type: _Float16
2424+
arguments:
2425+
- type: _Float16
2426+
guard: LIBC_TYPES_HAS_FLOAT16
24202427
- name: tanhf
24212428
standards:
24222429
- stdc

libc/src/math/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,7 @@ add_math_entrypoint_object(sqrtf128)
501501

502502
add_math_entrypoint_object(tan)
503503
add_math_entrypoint_object(tanf)
504+
add_math_entrypoint_object(tanf16)
504505

505506
add_math_entrypoint_object(tanh)
506507
add_math_entrypoint_object(tanhf)

libc/src/math/generic/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,25 @@ add_entrypoint_object(
662662
${libc_opt_high_flag}
663663
)
664664

665+
add_entrypoint_object(
666+
tanf16
667+
SRCS
668+
tanf16.cpp
669+
HDRS
670+
../tanf16.h
671+
DEPENDS
672+
.sincosf16_utils
673+
libc.hdr.errno_macros
674+
libc.hdr.fenv_macros
675+
libc.src.__support.FPUtil.cast
676+
libc.src.__support.FPUtil.fenv_impl
677+
libc.src.__support.FPUtil.fp_bits
678+
libc.src.__support.FPUtil.except_value_utils
679+
libc.src.__support.FPUtil.multiply_add
680+
libc.src.__support.macros.optimization
681+
libc.src.__support.macros.properties.types
682+
)
683+
665684
add_entrypoint_object(
666685
tanpif16
667686
SRCS

libc/src/math/generic/sincosf16_utils.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,11 @@ LIBC_INLINE int32_t range_reduction_sincospif16(float x, float &y) {
6363
// further intermediate computation.
6464
LIBC_INLINE int32_t range_reduction_sincosf16(float x, float &y) {
6565
double prod = x * 0x1.45f306dc9c883p3;
66-
double kf = fputil::nearest_integer(prod);
67-
y = static_cast<float>(prod - kf);
66+
double kd = fputil::nearest_integer(prod);
6867

69-
return static_cast<int32_t>(kf);
68+
y = static_cast<float>(prod - kd);
69+
70+
return static_cast<int32_t>(kd);
7071
}
7172

7273
static LIBC_INLINE void sincosf16_poly_eval(int32_t k, float y, float &sin_k,

libc/src/math/generic/tanf16.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//===-- Half-precision tan(x) function ------------------------------------===//
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+
#include "src/math/tanf16.h"
10+
#include "hdr/errno_macros.h"
11+
#include "hdr/fenv_macros.h"
12+
#include "sincosf16_utils.h"
13+
#include "src/__support/FPUtil/FEnvImpl.h"
14+
#include "src/__support/FPUtil/FPBits.h"
15+
#include "src/__support/FPUtil/cast.h"
16+
#include "src/__support/FPUtil/except_value_utils.h"
17+
#include "src/__support/FPUtil/multiply_add.h"
18+
#include "src/__support/macros/optimization.h"
19+
20+
namespace LIBC_NAMESPACE_DECL {
21+
22+
constexpr size_t N_EXCEPTS = 9;
23+
24+
constexpr fputil::ExceptValues<float16, N_EXCEPTS> TANF16_EXCEPTS{{
25+
// (input, RZ output, RU offset, RD offset, RN offset)
26+
{0x2894, 0x2894, 1, 0, 1},
27+
{0x3091, 0x3099, 1, 0, 0},
28+
{0x3098, 0x30a0, 1, 0, 0},
29+
{0x55ed, 0x3911, 1, 0, 0},
30+
{0x607b, 0xc638, 0, 1, 1},
31+
{0x674e, 0x3b7d, 1, 0, 0},
32+
{0x6807, 0x4014, 1, 0, 1},
33+
{0x6f4d, 0xbe19, 0, 1, 1},
34+
{0x7330, 0xcb62, 0, 1, 0},
35+
}};
36+
37+
LLVM_LIBC_FUNCTION(float16, tanf16, (float16 x)) {
38+
using FPBits = fputil::FPBits<float16>;
39+
FPBits xbits(x);
40+
41+
uint16_t x_u = xbits.uintval();
42+
uint16_t x_abs = x_u & 0x7fff;
43+
bool x_sign = x_u >> 15;
44+
float xf = x;
45+
46+
// Handle exceptional values
47+
if (auto r = TANF16_EXCEPTS.lookup_odd(x_abs, x_sign);
48+
LIBC_UNLIKELY(r.has_value()))
49+
return r.value();
50+
51+
// |x| <= 0x1.d1p-5
52+
if (LIBC_UNLIKELY(x_abs <= 0x2b44)) {
53+
if (LIBC_UNLIKELY(x_abs <= 0x10e6)) {
54+
// tan(+/-0) = +/-0
55+
if (LIBC_UNLIKELY(x_abs == 0U))
56+
return x;
57+
58+
int rounding = fputil::quick_get_round();
59+
60+
// Exhaustive tests show that, when:
61+
// x > 0, and rounding upward or
62+
// x < 0, and rounding downward then,
63+
// tan(x) = x * 2^-11 + x
64+
if ((xbits.is_pos() && rounding == FE_UPWARD) ||
65+
(xbits.is_neg() && rounding == FE_DOWNWARD))
66+
return fputil::cast<float16>(fputil::multiply_add(xf, 0x1.0p-11f, xf));
67+
else
68+
return x;
69+
}
70+
71+
float xsq = xf * xf;
72+
73+
float result = fputil::polyeval(xsq, 0x1p0f, 0x1.555556p-2f, 0x1.110ee4p-3f,
74+
0x1.be80f6p-5f);
75+
76+
return fputil::cast<float16>(xf * result);
77+
}
78+
79+
// tan(+/-inf)= NaN, and tan(NaN) = NaN
80+
if (LIBC_UNLIKELY(x_abs >= 0x7c00)) {
81+
if (x_abs == 0x7c00) {
82+
fputil::set_errno_if_required(EDOM);
83+
fputil::raise_except_if_required(FE_INVALID);
84+
}
85+
86+
return x + FPBits::quiet_nan().get_val();
87+
}
88+
89+
// Range reduction:
90+
// For |x| > pi/32, we perform range reduction as follows:
91+
// Find k and y such that:
92+
// x = (k + y) * pi/32;
93+
// k is an integer, |y| < 0.5
94+
//
95+
// This is done by performing:
96+
// k = round(x * 32/pi)
97+
// y = x * 32/pi - k
98+
//
99+
// Once k and y are computed, we then deduce the answer by the formula:
100+
// tan(x) = sin(x) / cos(x)
101+
// = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k)
102+
float sin_k, cos_k, sin_y, cosm1_y;
103+
sincosf16_eval(xf, sin_k, cos_k, sin_y, cosm1_y);
104+
105+
// Note that, cosm1_y = cos_y - 1:
106+
using fputil::multiply_add;
107+
return fputil::cast<float16>(
108+
multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) /
109+
multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k)));
110+
}
111+
112+
} // namespace LIBC_NAMESPACE_DECL

libc/src/math/generic/tanpif16.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ LLVM_LIBC_FUNCTION(float16, tanpif16, (float16 x)) {
7979
// k = round(x * 32)
8080
// y = x * 32 - k
8181
//
82-
// Once k and y are computed, we then deduce the answer by tthe formula:
82+
// Once k and y are computed, we then deduce the answer by the formula:
8383
// tan(x) = sin(x) / cos(x)
8484
// = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k)
8585
float xf = x;

libc/src/math/tanf16.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//===-- Implementation header for tanf16 ------------------------*- 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_MATH_TANF16_H
10+
#define LLVM_LIBC_SRC_MATH_TANF16_H
11+
12+
#include "src/__support/macros/config.h"
13+
#include "src/__support/macros/properties/types.h"
14+
15+
namespace LIBC_NAMESPACE_DECL {
16+
17+
float16 tanf16(float16 x);
18+
19+
} // namespace LIBC_NAMESPACE_DECL
20+
21+
#endif // LLVM_LIBC_SRC_MATH_TANF16_H

libc/test/src/math/CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,17 @@ add_fp_unittest(
190190
libc.src.__support.FPUtil.fp_bits
191191
)
192192

193+
add_fp_unittest(
194+
tanf16_test
195+
NEED_MPFR
196+
SUITE
197+
libc-math-unittests
198+
SRCS
199+
tanf16_test.cpp
200+
DEPENDS
201+
libc.src.math.tanf16
202+
)
203+
193204
add_fp_unittest(
194205
tanpif16_test
195206
NEED_MPFR

libc/test/src/math/cosf16_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
1717

1818
// Range: [0, Inf]
1919
static constexpr uint16_t POS_START = 0x0000U;
20-
static constexpr uint16_t POS_STOP = 0x7c00u;
20+
static constexpr uint16_t POS_STOP = 0x7c00U;
2121

2222
// Range: [-Inf, 0]
2323
static constexpr uint16_t NEG_START = 0x8000U;

0 commit comments

Comments
 (0)