diff --git a/libc/config/baremetal/aarch64/entrypoints.txt b/libc/config/baremetal/aarch64/entrypoints.txt index 582e7c52726f..1c04ee2b6d04 100644 --- a/libc/config/baremetal/aarch64/entrypoints.txt +++ b/libc/config/baremetal/aarch64/entrypoints.txt @@ -336,6 +336,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf libc.src.math.asinhf diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt index 98374e6cede7..ad6b6d922b57 100644 --- a/libc/config/baremetal/arm/entrypoints.txt +++ b/libc/config/baremetal/arm/entrypoints.txt @@ -339,6 +339,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf libc.src.math.asinhf diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt index b45b388ec963..29be47dfbfd5 100644 --- a/libc/config/baremetal/riscv/entrypoints.txt +++ b/libc/config/baremetal/riscv/entrypoints.txt @@ -338,6 +338,7 @@ set(TARGET_LIBM_ENTRYPOINTS # math.h entrypoints libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asinf libc.src.math.asinhf libc.src.math.asinpif diff --git a/libc/config/darwin/aarch64/entrypoints.txt b/libc/config/darwin/aarch64/entrypoints.txt index 5488bf1d0c7d..b4a1ee70764c 100644 --- a/libc/config/darwin/aarch64/entrypoints.txt +++ b/libc/config/darwin/aarch64/entrypoints.txt @@ -153,6 +153,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf libc.src.math.asinhf diff --git a/libc/config/gpu/amdgpu/entrypoints.txt b/libc/config/gpu/amdgpu/entrypoints.txt index 856bf1d55f3b..a65b6f0274fd 100644 --- a/libc/config/gpu/amdgpu/entrypoints.txt +++ b/libc/config/gpu/amdgpu/entrypoints.txt @@ -283,6 +283,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf libc.src.math.asinhf diff --git a/libc/config/gpu/nvptx/entrypoints.txt b/libc/config/gpu/nvptx/entrypoints.txt index 8765cf189f32..fee0038c88cc 100644 --- a/libc/config/gpu/nvptx/entrypoints.txt +++ b/libc/config/gpu/nvptx/entrypoints.txt @@ -283,6 +283,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf libc.src.math.asinhf diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt index d27dabaff5c1..960958b7cf90 100644 --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -423,6 +423,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf libc.src.math.asinhf diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt index 714bd024dad1..e76bf81670ce 100644 --- a/libc/config/linux/arm/entrypoints.txt +++ b/libc/config/linux/arm/entrypoints.txt @@ -253,6 +253,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf libc.src.math.asinhf diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index b823e1b25e6c..a69d1a1b0a64 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -427,6 +427,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf libc.src.math.asinhf diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index f1b3e90cfd03..bb4973628d58 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -469,6 +469,7 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf libc.src.math.asinhf diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt index d88a49c9850e..f777fc6c94bc 100644 --- a/libc/config/windows/entrypoints.txt +++ b/libc/config/windows/entrypoints.txt @@ -133,9 +133,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.acos libc.src.math.acosf libc.src.math.acoshf + libc.src.math.acospif libc.src.math.asin libc.src.math.asinf - libc.src.math.asinpif libc.src.math.asinhf libc.src.math.asinpif libc.src.math.atan2 diff --git a/libc/shared/math.h b/libc/shared/math.h index 97eb898a80ac..a7d735ffa174 100644 --- a/libc/shared/math.h +++ b/libc/shared/math.h @@ -16,6 +16,7 @@ #include "math/acosf16.h" #include "math/acoshf.h" #include "math/acoshf16.h" +#include "math/acospif.h" #include "math/acospif16.h" #include "math/asin.h" #include "math/asinf.h" diff --git a/libc/shared/math/acospif.h b/libc/shared/math/acospif.h new file mode 100644 index 000000000000..79a2ef697a85 --- /dev/null +++ b/libc/shared/math/acospif.h @@ -0,0 +1,23 @@ +//===-- Shared acospif header -----------------------------------*- 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_SHARED_MATH_ACOSPIF_H +#define LLVM_LIBC_SHARED_MATH_ACOSPIF_H + +#include "shared/libc_common.h" +#include "src/__support/math/acospif.h" + +namespace LIBC_NAMESPACE_DECL { +namespace shared { + +using math::acospif; + +} // namespace shared +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SHARED_MATH_ACOSPIF_H diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt index 8f61cfafee45..3bb8e76a54bf 100644 --- a/libc/src/__support/math/CMakeLists.txt +++ b/libc/src/__support/math/CMakeLists.txt @@ -94,6 +94,21 @@ add_header_library( libc.src.__support.macros.optimization ) +add_header_library( + acospif + HDRS + acospif.h + DEPENDS + .inv_trigf_utils + libc.src.__support.FPUtil.fenv_implt + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.sqrt + libc.src.__support.macros.optimization +) + add_header_library( acospif16 HDRS @@ -177,12 +192,11 @@ add_header_library( HDRS asinpif.h DEPENDS - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.polyeval - libc.src.__support.FPUtil.cast + .inv_trigf_utils libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.fp_bits libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval libc.src.__support.FPUtil.sqrt libc.src.__support.macros.optimization ) diff --git a/libc/src/__support/math/acospif.h b/libc/src/__support/math/acospif.h new file mode 100644 index 000000000000..15781f037f23 --- /dev/null +++ b/libc/src/__support/math/acospif.h @@ -0,0 +1,100 @@ +//===-- Implementation header for acospif -----------------------*- 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___SUPPORT_MATH_ACOSPIF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_ACOSPIF_H + +#include "inv_trigf_utils.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/sqrt.h" +#include "src/__support/macros/optimization.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { + +LIBC_INLINE float acospif(float x) { + using FPBits = fputil::FPBits; + + FPBits xbits(x); + bool is_neg = xbits.is_neg(); + double x_abs = fputil::cast(xbits.abs().get_val()); + + auto signed_result = [is_neg](auto r) -> auto { return is_neg ? -r : r; }; + + if (LIBC_UNLIKELY(x_abs > 1.0)) { + if (xbits.is_nan()) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + return x; + } + + fputil::raise_except_if_required(FE_INVALID); + fputil::set_errno_if_required(EDOM); + return FPBits::quiet_nan().get_val(); + } + + // acospif(x) = 1/2 - asinpif(x) + // + // if |x| <= 0.5: + // acospif(x) = 0.5 - x * (c0 + x^2 * P1(x^2)) + if (LIBC_UNLIKELY(x_abs <= 0.5)) { + double x_d = fputil::cast(x); + double v2 = x_d * x_d; + double result = x_d * fputil::multiply_add( + v2, inv_trigf_utils_internal::asinpi_eval(v2), + inv_trigf_utils_internal::ASINPI_COEFFS[0]); + return fputil::cast(0.5 - result); + } + + // If |x| > 0.5, we use the identity: + // asinpif(x) = sign(x) * (0.5 - 2 * sqrt(u) * P(u)) + // where u = (1 - |x|) / 2, P(u) ~ asin(sqrt(u)) / (pi * sqrt(u)) + // + // Then: + // acospif(x) = 0.5 - asinpif(x) + // + // For x > 0.5: + // acospif(x) = 0.5 - (0.5 - 2*sqrt(u)*P(u)) = 2*sqrt(u)*P(u) + // + // For x < -0.5: + // acospif(x) = 0.5 - (-(0.5 - 2*sqrt(u)*P(u))) = 1 - 2*sqrt(u)*P(u) + + constexpr double ONE_OVER_PI_HI = 0x1.45f306dc9c883p-2; + constexpr double ONE_OVER_PI_LO = -0x1.6b01ec5417056p-56; + // C0_MINUS_1OVERPI = c0 - 1/pi = DELTA_C0 + ONE_OVER_PI_LO + constexpr double C0_MINUS_1OVERPI = + (inv_trigf_utils_internal::ASINPI_COEFFS[0] - ONE_OVER_PI_HI) + + ONE_OVER_PI_LO; + + double u = fputil::multiply_add(-0.5, x_abs, 0.5); + double sqrt_u = fputil::sqrt(u); + double neg2_sqrt_u = -2.0 * sqrt_u; + + // tail = (c0 - 1/pi) + u * P1(u) + double tail = fputil::multiply_add( + u, inv_trigf_utils_internal::asinpi_eval(u), C0_MINUS_1OVERPI); + + double result_hi = fputil::multiply_add(neg2_sqrt_u, ONE_OVER_PI_HI, 0.5); + double result = fputil::multiply_add(tail, neg2_sqrt_u, result_hi); + + // For x > 0.5: acospif(x) = 2*sqrt(u)*P(u) + // For x < -0.5: acospif(x) = 1 - 2*sqrt(u)*P(u) + + return fputil::cast(0.5 - signed_result(result)); +} + +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ACOSPIF_H diff --git a/libc/src/__support/math/asinpif.h b/libc/src/__support/math/asinpif.h index 398d64b4f131..9a5daf6198a4 100644 --- a/libc/src/__support/math/asinpif.h +++ b/libc/src/__support/math/asinpif.h @@ -9,6 +9,7 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_MATH_ASINPIF_H #define LLVM_LIBC_SRC___SUPPORT_MATH_ASINPIF_H +#include "inv_trigf_utils.h" #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PolyEval.h" @@ -66,50 +67,14 @@ LIBC_INLINE float asinpif(float x) { return r.value(); #endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // the coefficients for the polynomial approximation of asin(x)/(pi*x) in the - // range [0, 0.5] extracted using Sollya. - // - // Sollya code: - // > prec = 200; - // > display = hexadecimal; - // > g = asin(x) / (pi * x); - // > P = fpminimax(g, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20|], - // > [|D...|], [0, 0.5]); - // > for i from 0 to degree(P) do coeff(P, i); - // > print("Error:", dirtyinfnorm(P - g, [1e-30; 0.25])); - // Error: 0x1.45c281e1cf9b58p-50 ~= 2^−49.652 - // - // Non-zero coefficients (even powers only): - constexpr double ASINPI_POLY_COEFFS[] = { - 0x1.45f306dc9c881p-2, // x^0 - 0x1.b2995e7b7e756p-5, // x^2 - 0x1.8723a1d12f828p-6, // x^4 - 0x1.d1a45564b9545p-7, // x^6 - 0x1.3ce4ceaa0e1e9p-7, // x^8 - 0x1.d2c305898ea13p-8, // x^10 - 0x1.692212e27a5f9p-8, // x^12 - 0x1.2b22cc744d25bp-8, // x^14 - 0x1.8427b864479ffp-9, // x^16 - 0x1.815522d7a2bf1p-8, // x^18 - -0x1.f6df98438aef4p-9, // x^20 - 0x1.4b50c2eb13708p-7 // x^22 - }; - // Evaluates P1(v2) = c1 + c2*v2 + c3*v2^2 + ... (tail of P without c0) - auto asinpi_polyeval = [&](double v2) -> double { - return fputil::polyeval( - v2, ASINPI_POLY_COEFFS[1], ASINPI_POLY_COEFFS[2], ASINPI_POLY_COEFFS[3], - ASINPI_POLY_COEFFS[4], ASINPI_POLY_COEFFS[5], ASINPI_POLY_COEFFS[6], - ASINPI_POLY_COEFFS[7], ASINPI_POLY_COEFFS[8], ASINPI_POLY_COEFFS[9], - ASINPI_POLY_COEFFS[10], ASINPI_POLY_COEFFS[11]); - }; - // if |x| <= 0.5: // asinpi(x) = x * (c0 + x^2 * P1(x^2)) if (LIBC_UNLIKELY(x_abs <= 0.5)) { double x_d = fputil::cast(x); double v2 = x_d * x_d; - double result = x_d * fputil::multiply_add(v2, asinpi_polyeval(v2), - ASINPI_POLY_COEFFS[0]); + double result = x_d * fputil::multiply_add( + v2, inv_trigf_utils_internal::asinpi_eval(v2), + inv_trigf_utils_internal::ASINPI_COEFFS[0]); return fputil::cast(result); } @@ -131,14 +96,16 @@ LIBC_INLINE float asinpif(float x) { constexpr double ONE_OVER_PI_LO = -0x1.6b01ec5417056p-56; // C0_MINUS_1OVERPI = c0 - 1/pi = DELTA_C0 + ONE_OVER_PI_LO constexpr double C0_MINUS_1OVERPI = - (ASINPI_POLY_COEFFS[0] - ONE_OVER_PI_HI) + ONE_OVER_PI_LO; + (inv_trigf_utils_internal::ASINPI_COEFFS[0] - ONE_OVER_PI_HI) + + ONE_OVER_PI_LO; double u = fputil::multiply_add(-0.5, x_abs, 0.5); double sqrt_u = fputil::sqrt(u); double neg2_sqrt_u = -2.0 * sqrt_u; // tail = (c0 - 1/pi) + u * P1(u) - double tail = fputil::multiply_add(u, asinpi_polyeval(u), C0_MINUS_1OVERPI); + double tail = fputil::multiply_add( + u, inv_trigf_utils_internal::asinpi_eval(u), C0_MINUS_1OVERPI); double result_hi = fputil::multiply_add(neg2_sqrt_u, ONE_OVER_PI_HI, 0.5); double result = fputil::multiply_add(tail, neg2_sqrt_u, result_hi); diff --git a/libc/src/__support/math/inv_trigf_utils.h b/libc/src/__support/math/inv_trigf_utils.h index 6eab68d8bbe0..7a93831333db 100644 --- a/libc/src/__support/math/inv_trigf_utils.h +++ b/libc/src/__support/math/inv_trigf_utils.h @@ -177,6 +177,43 @@ LIBC_INLINE double asin_eval(double xsq) { return fputil::multiply_add(xsq, r2, r1); } +// the coefficients for the polynomial approximation of asin(x)/(pi*x) in the +// range [0, 0.5] extracted using Sollya. +// +// Sollya code: +// > prec = 200; +// > display = hexadecimal; +// > g = asin(x) / (pi * x); +// > P = fpminimax(g, [|0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20|], +// > [|D...|], [0, 0.5]); +// > for i from 0 to degree(P) do coeff(P, i); +// > print("Error:", dirtyinfnorm(P - g, [1e-30; 0.25])); +// Error: 0x1.45c281e1cf9b58p-50 ~= 2^−49.652 +// +// Non-zero coefficients (even powers only): +LIBC_INLINE_VAR constexpr double ASINPI_COEFFS[13] = { + 0x1.45f306dc9c881p-2, // x^0 + 0x1.b2995e7b7e756p-5, // x^2 + 0x1.8723a1d12f828p-6, // x^4 + 0x1.d1a45564b9545p-7, // x^6 + 0x1.3ce4ceaa0e1e9p-7, // x^8 + 0x1.d2c305898ea13p-8, // x^10 + 0x1.692212e27a5f9p-8, // x^12 + 0x1.2b22cc744d25bp-8, // x^14 + 0x1.8427b864479ffp-9, // x^16 + 0x1.815522d7a2bf1p-8, // x^18 + -0x1.f6df98438aef4p-9, // x^20 + 0x1.4b50c2eb13708p-7 // x^22 +}; + +// Evaluates P1(v2) = c1 + c2*v2 + c3*v2^2 + ... (tail of P without c0) +LIBC_INLINE double asinpi_eval(double v2) { + return fputil::polyeval( + v2, ASINPI_COEFFS[1], ASINPI_COEFFS[2], ASINPI_COEFFS[3], + ASINPI_COEFFS[4], ASINPI_COEFFS[5], ASINPI_COEFFS[6], ASINPI_COEFFS[7], + ASINPI_COEFFS[8], ASINPI_COEFFS[9], ASINPI_COEFFS[10], ASINPI_COEFFS[11]); +} + } // namespace inv_trigf_utils_internal } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index 7a9370fe487e..e61795036899 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -48,6 +48,7 @@ add_math_entrypoint_object(acosh) add_math_entrypoint_object(acoshf) add_math_entrypoint_object(acoshf16) +add_math_entrypoint_object(acospif) add_math_entrypoint_object(acospif16) add_math_entrypoint_object(asin) diff --git a/libc/src/math/acospif.h b/libc/src/math/acospif.h new file mode 100644 index 000000000000..80e001a60d1a --- /dev/null +++ b/libc/src/math/acospif.h @@ -0,0 +1,20 @@ +//===-- Implementation header for acospif -----------------------*- 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_ACOSPIF_H +#define LLVM_LIBC_SRC_MATH_ACOSPIF_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +float acospif(float x); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_MATH_ACOSPIF_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 1890e0b1467a..f8ec25be61d1 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -3963,6 +3963,16 @@ add_entrypoint_object( libc.src.errno.errno ) +add_entrypoint_object( + acospif + SRCS + acospif.cpp + HDRS + ../acospif.h + DEPENDS + libc.src.__support.math.acospif +) + add_entrypoint_object( asinhf SRCS diff --git a/libc/src/math/generic/acospif.cpp b/libc/src/math/generic/acospif.cpp new file mode 100644 index 000000000000..928c2cba1441 --- /dev/null +++ b/libc/src/math/generic/acospif.cpp @@ -0,0 +1,16 @@ +//===-- Single-precision acospif(x) 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/acospif.h" +#include "src/__support/math/acospif.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(float, acospif, (float x)) { return math::acospif(x); } + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt index 0c934d6703c7..a04a15cdabcb 100644 --- a/libc/test/shared/CMakeLists.txt +++ b/libc/test/shared/CMakeLists.txt @@ -13,6 +13,7 @@ add_fp_unittest( libc.src.__support.math.acosf16 libc.src.__support.math.acoshf libc.src.__support.math.acoshf16 + libc.src.__support.math.acospif libc.src.__support.math.acospif16 libc.src.__support.math.asin libc.src.__support.math.asinf diff --git a/libc/test/shared/shared_math_test.cpp b/libc/test/shared/shared_math_test.cpp index 66c986dda4f2..460449e4fcb2 100644 --- a/libc/test/shared/shared_math_test.cpp +++ b/libc/test/shared/shared_math_test.cpp @@ -148,6 +148,7 @@ TEST(LlvmLibcSharedMathTest, AllFloat) { EXPECT_FP_EQ(0x1.921fb6p+0, LIBC_NAMESPACE::shared::acosf(0.0f)); EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::acoshf(1.0f)); + EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::acospif(1.0f)); EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::asinf(0.0f)); EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::asinhf(0.0f)); EXPECT_FP_EQ(0x0p+0f, LIBC_NAMESPACE::shared::asinpif(0.0f)); diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 47c05c650c70..73b5ebf5a856 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -2533,6 +2533,17 @@ add_fp_unittest( libc.src.math.acosf16 ) +add_fp_unittest( + acospif_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + acospif_test.cpp + DEPENDS + libc.src.math.acospif +) + add_fp_unittest( acospif16_test NEED_MPFR diff --git a/libc/test/src/math/acospif_test.cpp b/libc/test/src/math/acospif_test.cpp new file mode 100644 index 000000000000..96215bdc577e --- /dev/null +++ b/libc/test/src/math/acospif_test.cpp @@ -0,0 +1,29 @@ +//===-- Unittests for acospif (MPFR) --------------------------------------===// +// +// 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/acospif.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +using LlvmLibcAcospifTest = LIBC_NAMESPACE::testing::FPTest; + +TEST_F(LlvmLibcAcospifTest, InFloatRange) { + constexpr uint32_t COUNT = 100'000; + // Test in [-1, 1] + const uint32_t STEP = 0x3F800000 / COUNT; // step through [0, 1.0f] in bits + for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) { + float x = FPBits(v).get_val(); + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acospi, x, + LIBC_NAMESPACE::acospif(x), 0.5); + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acospi, -x, + LIBC_NAMESPACE::acospif(-x), 0.5); + } +} diff --git a/libc/test/src/math/asinpif_test.cpp b/libc/test/src/math/asinpif_test.cpp index 073d11bc53f2..72fda596131b 100644 --- a/libc/test/src/math/asinpif_test.cpp +++ b/libc/test/src/math/asinpif_test.cpp @@ -15,24 +15,15 @@ namespace mpfr = LIBC_NAMESPACE::testing::mpfr; using LlvmLibcAsinpifTest = LIBC_NAMESPACE::testing::FPTest; -static constexpr mpfr::RoundingMode ROUNDING_MODES[] = { - mpfr::RoundingMode::Nearest, - mpfr::RoundingMode::Upward, - mpfr::RoundingMode::Downward, - mpfr::RoundingMode::TowardZero, -}; - TEST_F(LlvmLibcAsinpifTest, InFloatRange) { constexpr uint32_t COUNT = 100'000; // Test in [-1, 1] const uint32_t STEP = 0x3F800000 / COUNT; // step through [0, 1.0f] in bits - for (mpfr::RoundingMode rm : ROUNDING_MODES) { - for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) { - float x = FPBits(v).get_val(); - ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinpi, x, - LIBC_NAMESPACE::asinpif(x), 0.5); - ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinpi, -x, - LIBC_NAMESPACE::asinpif(-x), 0.5); - } + for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) { + float x = FPBits(v).get_val(); + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinpi, x, + LIBC_NAMESPACE::asinpif(x), 0.5); + ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinpi, -x, + LIBC_NAMESPACE::asinpif(-x), 0.5); } } diff --git a/libc/test/src/math/exhaustive/CMakeLists.txt b/libc/test/src/math/exhaustive/CMakeLists.txt index 877d653a2629..a21e208312c5 100644 --- a/libc/test/src/math/exhaustive/CMakeLists.txt +++ b/libc/test/src/math/exhaustive/CMakeLists.txt @@ -502,6 +502,22 @@ add_fp_unittest( -lpthread ) +add_fp_unittest( + acospif_test + NO_RUN_POSTBUILD + NEED_MPFR + SUITE + libc_math_exhaustive_tests + SRCS + acospif_test.cpp + DEPENDS + .exhaustive_test + libc.src.math.acospif + libc.src.__support.FPUtil.fp_bits + LINK_LIBRARIES + -lpthread +) + add_fp_unittest( asinhf_test NO_RUN_POSTBUILD diff --git a/libc/test/src/math/exhaustive/acospif_test.cpp b/libc/test/src/math/exhaustive/acospif_test.cpp new file mode 100644 index 000000000000..fcc6a774617f --- /dev/null +++ b/libc/test/src/math/exhaustive/acospif_test.cpp @@ -0,0 +1,33 @@ +//===-- Exhaustive test for acospif ---------------------------------------===// +// +// 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/acospif.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +using LlvmLibcAsinfExhaustiveTest = + LlvmLibcUnaryOpExhaustiveMathTest; + +// Range: [0, Inf]; +static constexpr uint32_t POS_START = 0x0000'0000U; +static constexpr uint32_t POS_STOP = 0x7f80'0000U; + +TEST_F(LlvmLibcAsinfExhaustiveTest, 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(LlvmLibcAsinfExhaustiveTest, NegativeRange) { + test_full_range_all_roundings(NEG_START, NEG_STOP); +} diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 88028d90d2d5..3d52873c40bb 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -4819,6 +4819,18 @@ add_fp_unittest( libc.src.math.acosf16 ) +add_fp_unittest( + acospif_test + SUITE + libc-math-smoke-tests + SRCS + acospif_test.cpp + DEPENDS + libc.hdr.errno_macros + libc.src.math.acospif + libc.src.__support.FPUtil.fp_bits +) + add_fp_unittest( acospif16_test SUITE diff --git a/libc/test/src/math/smoke/acospif_test.cpp b/libc/test/src/math/smoke/acospif_test.cpp new file mode 100644 index 000000000000..ccee9a25de5e --- /dev/null +++ b/libc/test/src/math/smoke/acospif_test.cpp @@ -0,0 +1,51 @@ +//===-- Unittests for acospif ---------------------------------------------===// +// +// 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 "hdr/errno_macros.h" +#include "hdr/math_macros.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/math/acospif.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +#include "hdr/stdint_proxy.h" + +using LlvmLibcAcospifTest = LIBC_NAMESPACE::testing::FPTest; + +TEST_F(LlvmLibcAcospifTest, SpecialNumbers) { + EXPECT_FP_EQ_WITH_EXCEPTION(aNaN, LIBC_NAMESPACE::acospif(sNaN), FE_INVALID); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acospif(aNaN)); + EXPECT_MATH_ERRNO(0); + + // acospif(0) = 0.5 + EXPECT_FP_EQ(0.5f, LIBC_NAMESPACE::acospif(0.0f)); + EXPECT_MATH_ERRNO(0); + // acospif(-0) = 0.5 + EXPECT_FP_EQ(0.5f, LIBC_NAMESPACE::acospif(-0.0f)); + EXPECT_MATH_ERRNO(0); + // acospif(1) = 0 + EXPECT_FP_EQ(0.0f, LIBC_NAMESPACE::acospif(1.0f)); + EXPECT_MATH_ERRNO(0); + // acospif(-1) = 1 + EXPECT_FP_EQ(1.0f, LIBC_NAMESPACE::acospif(-1.0f)); + EXPECT_MATH_ERRNO(0); + + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acospif(inf)); + EXPECT_MATH_ERRNO(EDOM); + + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acospif(neg_inf)); + EXPECT_MATH_ERRNO(EDOM); + + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acospif(2.0f)); + EXPECT_MATH_ERRNO(EDOM); + + EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::acospif(-2.0f)); + EXPECT_MATH_ERRNO(EDOM); +} diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel index 29650c1e20f9..c6ed630ab02a 100644 --- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel @@ -2597,6 +2597,22 @@ libc_support_library( ], ) +libc_support_library( + name = "__support_math_acospif", + hdrs = ["src/__support/math/acospif.h"], + deps = [ + ":__support_fputil_cast", + ":__support_fputil_fenv_impl", + ":__support_fputil_fp_bits", + ":__support_fputil_multiply_add", + ":__support_fputil_polyeval", + ":__support_fputil_sqrt", + ":__support_macros_config", + ":__support_macros_optimization", + ":__support_math_inv_trigf_utils", + ], +) + libc_support_library( name = "__support_math_acospif16", hdrs = ["src/__support/math/acospif16.h"], @@ -2847,6 +2863,7 @@ libc_support_library( ":__support_fputil_sqrt", ":__support_macros_config", ":__support_macros_optimization", + ":__support_math_inv_trigf_utils", ], ) @@ -5878,6 +5895,13 @@ libc_math_function( ], ) +libc_math_function( + name = "acospif", + additional_deps = [ + ":__support_math_acospif", + ], +) + libc_math_function( name = "acospif16", additional_deps = [