Skip to content

[libc][math][c23] implement C23 math function tanpif #147192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.tan
libc.src.math.tanf
libc.src.math.tanhf
libc.src.math.tanpif
libc.src.math.totalorder
libc.src.math.totalorderf
libc.src.math.totalorderl
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ set(TARGET_LIBM_ENTRYPOINTS
libc.src.math.tan
libc.src.math.tanf
libc.src.math.tanhf
libc.src.math.tanpif
libc.src.math.totalorder
libc.src.math.totalorderf
libc.src.math.totalorderl
Expand Down
2 changes: 1 addition & 1 deletion libc/docs/headers/math/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ Higher Math Functions
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| tanh | |check| | | | |check| | | 7.12.5.6 | F.10.2.6 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| tanpi | | | | |check| | | 7.12.4.14 | F.10.1.14 |
| tanpi | |check| | | | |check| | | 7.12.4.14 | F.10.1.14 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| tgamma | | | | | | 7.12.8.4 | F.10.5.4 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
Expand Down
6 changes: 6 additions & 0 deletions libc/include/math.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2524,6 +2524,12 @@ functions:
arguments:
- type: _Float16
guard: LIBC_TYPES_HAS_FLOAT16
- name: tanpif
standards:
- stdc
return_type: float
arguments:
- type: float
- name: tanpif16
standards:
- stdc
Expand Down
2 changes: 2 additions & 0 deletions libc/src/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,8 @@ add_math_entrypoint_object(tanf16)
add_math_entrypoint_object(tanh)
add_math_entrypoint_object(tanhf)
add_math_entrypoint_object(tanhf16)

add_math_entrypoint_object(tanpif)
add_math_entrypoint_object(tanpif16)

add_math_entrypoint_object(tgamma)
Expand Down
15 changes: 15 additions & 0 deletions libc/src/math/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,21 @@ add_entrypoint_object(
libc.src.__support.macros.properties.types
)

add_entrypoint_object(
tanpif
SRCS
tanpif.cpp
HDRS
../tanpif.h
DEPENDS
.sincosf_utils
libc.src.__support.FPUtil.except_value_utils
libc.src.__support.FPUtil.fenv_impl
libc.src.__support.FPUtil.fp_bits
libc.src.__support.FPUtil.multiply_add
libc.src.__support.macros.optimization
)

add_entrypoint_object(
tanpif16
SRCS
Expand Down
106 changes: 106 additions & 0 deletions libc/src/math/generic/tanpif.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//===-- Single-precision tanpi function -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/math/tanpif.h"
#include "sincosf_utils.h"
#include "src/__support/FPUtil/FEnvImpl.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/cast.h"
#include "src/__support/FPUtil/except_value_utils.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY

namespace LIBC_NAMESPACE_DECL {

#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
constexpr size_t N_EXCEPTS = 3;

constexpr fputil::ExceptValues<float, N_EXCEPTS> TANPIF_EXCEPTS{{
// (input, RZ output, RU offset, RD offset, RN offset)
{0x38F26685, 0x39BE6182, 1, 0, 0},
{0x3E933802, 0x3FA267DD, 1, 0, 0},
{0x3F3663FF, 0xBFA267DD, 0, 1, 0},
}};
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS

LLVM_LIBC_FUNCTION(float, tanpif, (float x)) {
using FPBits = typename fputil::FPBits<float>;
FPBits xbits(x);

uint32_t x_u = xbits.uintval();
uint32_t x_abs = x_u & 0x7fff'ffffU;
double xd = static_cast<double>(xbits.get_val());

// Handle exceptional values
if (LIBC_UNLIKELY(x_abs <= 0x3F3663FF)) {
if (LIBC_UNLIKELY(x_abs == 0U))
return x;

#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
bool x_sign = x_u >> 31;

if (auto r = TANPIF_EXCEPTS.lookup_odd(x_abs, x_sign);
LIBC_UNLIKELY(r.has_value()))
return r.value();
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
}

// Numbers greater or equal to 2^23 are always integers, or infinity, or NaN
if (LIBC_UNLIKELY(x_abs >= 0x4B00'0000)) {
// x is inf or NaN.
if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) {
if (xbits.is_signaling_nan()) {
fputil::raise_except_if_required(FE_INVALID);
return FPBits::quiet_nan().get_val();
}

if (x_abs == 0x7f80'0000U) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_INVALID);
}

return x + FPBits::quiet_nan().get_val();
}

return FPBits::zero(xbits.sign()).get_val();
}

// Range reduction:
// For |x| > 1/32, we perform range reduction as follows:
// Find k and y such that:
// x = (k + y) * 1/32
// k is an integer
// |y| < 0.5
//
// This is done by performing:
// k = round(x * 32)
// y = x * 32 - k
//
// Once k and y are computed, we then deduce the answer by the formula:
// tan(x) = sin(x) / cos(x)
// = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k)
double sin_k, cos_k, sin_y, cosm1_y;
sincospif_eval(xd, sin_k, cos_k, sin_y, cosm1_y);

if (LIBC_UNLIKELY(sin_y == 0 && cos_k == 0)) {
fputil::set_errno_if_required(EDOM);
fputil::raise_except_if_required(FE_DIVBYZERO);

int32_t x_mp5_u = static_cast<int32_t>(x - 0.5);
return ((x_mp5_u & 0x1) ? -1 : 1) * FPBits::inf().get_val();
}

using fputil::multiply_add;
return fputil::cast<float>(
multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) /
multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k)));
}

} // namespace LIBC_NAMESPACE_DECL
20 changes: 20 additions & 0 deletions libc/src/math/tanpif.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for tanpif ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_MATH_TANPIF_H
#define LLVM_LIBC_SRC_MATH_TANPIF_H

#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

float tanpif(float x);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_MATH_TANPIF_H
16 changes: 16 additions & 0 deletions libc/test/src/math/exhaustive/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@ add_fp_unittest(
-lpthread
)

add_fp_unittest(
tanpif_test
NO_RUN_POSTBUILD
NEED_MPFR
SUITE
libc_math_exhaustive_tests
SRCS
tanpif_test.cpp
DEPENDS
.exhaustive_test
libc.src.math.tanpif
libc.src.__support.FPUtil.fp_bits
LINK_LIBRARIES
-lpthread
)

add_fp_unittest(
erff_test
NO_RUN_POSTBUILD
Expand Down
33 changes: 33 additions & 0 deletions libc/test/src/math/exhaustive/tanpif_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//===-- Exhaustive test for tanpif ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "exhaustive_test.h"
#include "src/math/tanpif.h"
#include "utils/MPFRWrapper/MPFRUtils.h"

namespace mpfr = LIBC_NAMESPACE::testing::mpfr;

using LlvmLibcTanpifExhaustiveTest =
LlvmLibcUnaryOpExhaustiveMathTest<float, mpfr::Operation::Tanpi,
LIBC_NAMESPACE::tanpif>;

// Range: [0, Inf];
static constexpr uint32_t POS_START = 0x0000'0000U;
static constexpr uint32_t POS_STOP = 0x7f80'0000U;

TEST_F(LlvmLibcTanpifExhaustiveTest, PostiveRange) {
test_full_range_all_roundings(POS_START, POS_STOP);
}

// Range: [-Inf, 0];
static constexpr uint32_t NEG_START = 0xb000'0000U;
static constexpr uint32_t NEG_STOP = 0xff80'0000U;

TEST_F(LlvmLibcTanpifExhaustiveTest, NegativeRange) {
test_full_range_all_roundings(NEG_START, NEG_STOP);
}
11 changes: 11 additions & 0 deletions libc/test/src/math/smoke/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,17 @@ add_fp_unittest(
libc.src.math.tanf16
)

add_fp_unittest(
tanpif_test
SUITE
libc-math-smoke-tests
SRCS
tanpif_test.cpp
DEPENDS
libc.src.errno.errno
libc.src.math.tanpif
)

add_fp_unittest(
tanpif16_test
SUITE
Expand Down
36 changes: 36 additions & 0 deletions libc/test/src/math/smoke/tanpif_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===-- Unittests for tanpif ----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/libc_errno.h"
#include "src/math/tanpif.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"

using LlvmLibcTanpifTest = LIBC_NAMESPACE::testing::FPTest<float>;

TEST_F(LlvmLibcTanpifTest, SpecialNumbers) {
libc_errno = 0;

EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::tanpif(sNaN), FE_INVALID);
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::tanpif(aNaN));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ(zero, LIBC_NAMESPACE::tanpif(zero));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::tanpif(neg_zero));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::tanpif(inf));
EXPECT_MATH_ERRNO(EDOM);

EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::tanpif(neg_inf));
EXPECT_MATH_ERRNO(EDOM);
}
Loading