[libc-commits] [libc] [libc][math][c23] implement C23 math function asinpif16 (PR #146226)
Mohamed Emad via libc-commits
libc-commits at lists.llvm.org
Sun Jun 29 21:15:05 PDT 2025
https://github.com/hulxv updated https://github.com/llvm/llvm-project/pull/146226
>From 790f1c42e74d1c2daf6133ec04ae542bcc00c2f6 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Fri, 27 Jun 2025 02:58:36 +0300
Subject: [PATCH 01/19] [libc][math][c23] implement C23 math function
`asinpif16`
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/docs/headers/math/index.rst | 2 +-
libc/include/math.yaml | 9 +-
libc/src/math/asinpif16.h | 21 +++
libc/src/math/generic/CMakeLists.txt | 16 ++
libc/src/math/generic/asinpif16.cpp | 191 ++++++++++++++++++++++
7 files changed, 239 insertions(+), 2 deletions(-)
create mode 100644 libc/src/math/asinpif16.h
create mode 100644 libc/src/math/generic/asinpif16.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index be5f5a66016b5..240d48f5bcdb8 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -651,6 +651,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
list(APPEND TARGET_LIBM_ENTRYPOINTS
# math.h C23 _Float16 entrypoints
# libc.src.math.acoshf16
+ libc.src.math.asinpif16
libc.src.math.canonicalizef16
libc.src.math.ceilf16
libc.src.math.copysignf16
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 73dfeae1a2c94..c9e5b0096099f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -664,6 +664,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
libc.src.math.acoshf16
libc.src.math.asinf16
libc.src.math.asinhf16
+ libc.src.math.asinpif16
libc.src.math.canonicalizef16
libc.src.math.ceilf16
libc.src.math.copysignf16
diff --git a/libc/docs/headers/math/index.rst b/libc/docs/headers/math/index.rst
index 947bd4b60b391..aaacc3ca92832 100644
--- a/libc/docs/headers/math/index.rst
+++ b/libc/docs/headers/math/index.rst
@@ -259,7 +259,7 @@ Higher Math Functions
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| asinh | |check| | | | |check| | | 7.12.5.2 | F.10.2.2 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
-| asinpi | | | | | | 7.12.4.9 | F.10.1.9 |
+| asinpi | | | | |check| | | 7.12.4.9 | F.10.1.9 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| atan | |check| | 1 ULP | | | | 7.12.4.3 | F.10.1.3 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
diff --git a/libc/include/math.yaml b/libc/include/math.yaml
index fef829422244d..b49c17b871a93 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -71,7 +71,14 @@ functions:
- stdc
return_type: double
arguments:
- - type: double
+ - type: double
+ - name: asinpif16
+ standards:
+ - stdc
+ return_type: _Float16
+ arguments:
+ - type: _Float16
+ guard: LIBC_TYPES_HAS_FLOAT16
- name: atan2
standards:
- stdc
diff --git a/libc/src/math/asinpif16.h b/libc/src/math/asinpif16.h
new file mode 100644
index 0000000000000..67ccb4ff4ac3d
--- /dev/null
+++ b/libc/src/math/asinpif16.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for asinpif16 ---------------------*- 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_ASINFPI16_H
+#define LLVM_LIBC_SRC_MATH_ASINFPI16_H
+
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/properties/types.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+float16 asinpif16(float16 x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_MATH_ASINPIF16_H
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index adbed5b2de48c..76accf72058d3 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -4017,6 +4017,22 @@ add_entrypoint_object(
libc.src.__support.macros.properties.types
)
+add_entrypoint_object(
+ asinpif16
+ SRCS
+ asinpif16.cpp
+ HDRS
+ ../asinpif16.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.fenv_macros
+ libc.src.__support.FPUtil.cast
+ 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(
atanhf
SRCS
diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp
new file mode 100644
index 0000000000000..7de675211e5d2
--- /dev/null
+++ b/libc/src/math/generic/asinpif16.cpp
@@ -0,0 +1,191 @@
+//===-- Half-precision asinf16(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 "hdr/errno_macros.h"
+#include "hdr/fenv_macros.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"
+#include "src/math/asinfpi16.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+static constexpr float16 ONE_OVER_TWO = 0x3800; // 0.5f16
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+static constexpr size_t N_ASINFPI_EXCEPTS = 9;
+
+static constexpr float16 ONE_OVER_THREE = 0x3555; // 0.333251953125f16
+static constexpr float16 ONE_OVER_FOUR = 0x3400; // 0.25f16
+static constexpr float16 ONE_OVER_SIX = 0x32ab; // 0.166748046875f16
+
+static constexpr fputil::ExceptValues<float16, N_ASINFPI_EXCEPTS>
+ ASINFPI_EXCEPTS{{
+ // (input_hex, RZ_output_hex, RU_offset, RD_offset, RN_offset)
+
+ // x = 0.0, asinfpi(0.0) = 0.0
+ {0x0000, 0x0000, 0, 0, 0},
+
+ // x = 1.0, asinfpi(1.0) = 0.5
+ {0x3C00, ONE_OVER_TWO.uintval(), 0, 0, 0},
+
+ // x = -1.0, asinfpi(-1.0) = -0.5
+ {0xBC00, (fputil::FPBits<float16>(-ONE_OVER_TWO)).uintval(), 0, 0, 0},
+
+ // x = 0.5, asinfpi(0.5) = 1/6
+ {0x3800, ONE_OVER_SIX.uintval(), 0, 0, 0},
+
+ // x = -0.5, asinfpi(-0.5) = -1/6
+ {0xB800, (fputil::FPBits<float16>(-ONE_OVER_SIX)).uintval(), 0, 0, 0},
+
+ // x = sqrt(2)/2 ~ 0.70710678, asinfpi(x) = 1/4
+ // 0x3B41 is float16 for ~0.707. 0x3400 is float16 for 0.25
+ {0x3B41, ONE_OVER_FOUR.uintval(), 0, 0, 0},
+
+ // x = -sqrt(2)/2 ~ -0.70710678, asinfpi(x) = -1/4
+ {0xBB41, (fputil::FPBits<float16>(-ONE_OVER_FOUR)).uintval(), 0, 0, 0},
+
+ // x = sqrt(3)/2 ~ 0.8660254, asinfpi(x) = 1/3
+ // 0x3BF2 is float16 for ~0.866. 0x3555 is float16 for 1/3
+ {0x3BF2, ONE_OVER_THREE.uintval(), 0, 0, 0},
+
+ // x = -sqrt(3)/2 ~ -0.8660254, asinfpi(x) = -1/3
+ {0xBBF2, (fputil::FPBits<float16>(-ONE_OVER_THREE)).uintval(), 0, 0, 0},
+ }};
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
+ using FPBits = fputil::FPBits<float16>;
+
+ FPBits xbits(x);
+ uint16_t x_uint = xbits.uintval();
+ uint16_t x_abs = xbits.uintval() & 0x7fffU;
+ uint16_t x_sign = x_uint >> 15;
+
+ if (LIBC_UNLIKELY(x_abs > 0x3c00)) {
+ // aspinf16(NaN) = NaN
+ if (xbits.is_nan()) {
+ if (xbits.is_signaling_nan()) {
+ fputil::raise_except_if_required(FE_INVALID);
+ return FPBits::quiet_nan().get_val();
+ }
+ return x;
+ }
+
+ // 1 < |x| <= +/-inf
+ fputil::raise_except_if_required(FE_INVALID);
+ fputil::set_errno_if_required(EDOM);
+
+ return FPBits::quiet_nan().get_val();
+ }
+
+#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+ // Handle exceptional values
+ if (auto r = ACOSF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
+ return r.value();
+
+#else
+ // Handling zero
+ if (LIBC_UNLIKELY(x_abs == 0x0000)) {
+ return x;
+ }
+
+ // Handling +/-1.0
+ // If x is +/-1.0, return +/-0.5
+ if (LIBC_UNLIKELY(x_abs == 0x3c00)) {
+ return fputil::cast<float16>(x_sign ? -ONE_OVER_TWO : ONE_OVER_TWO);
+ }
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+ // the coefficients for the polynomial approximation of asin(x)/pi in the
+ // range [0, 0.5] extracted using python-sympy
+ //
+ // Python code to generate the coefficients:
+ // from sympy import *
+ // import math
+ // x = symbols('x')
+ // print(series(asin(x)/math.pi, x, 0, 21))
+ //
+ // OUTPUT:
+ //
+ // 0.318309886183791*x + 0.0530516476972984*x**3 + 0.0238732414637843*x**5 +
+ // 0.0142102627760621*x**7 + 0.00967087327815336*x**9 +
+ // 0.00712127941391293*x**11 + 0.00552355646848375*x**13 +
+ // 0.00444514782463692*x**15 + 0.00367705242846804*x**17 +
+ // 0.00310721681820837*x**19 + O(x**21)
+ //
+ // it's very accurate in the range [0, 0.5] and has a maximum error of
+ // 0.0000000000000001 in the range [0, 0.5].
+ static constexpr float16 POLY_COEFFS[10] = {
+ 0.318309886183791f16, // x^1
+ 0.0530516476972984f16, // x^3
+ 0.0238732414637843f16, // x^5
+ 0.0142102627760621f16, // x^7
+ 0.00967087327815336f16, // x^9
+ 0.00712127941391293f16, // x^11
+ 0.00552355646848375f16, // x^13
+ 0.00444514782463692f16, // x^15
+ 0.00367705242846804f16, // x^17
+ 0.00310721681820837f16 // x^19
+ };
+
+ // polynomial evaluation using horner's method
+ // work only for |x| in [0, 0.5]
+ auto __asinpi_polyeval = [](float16 xsq) -> float16 {
+ return fputil::polyeval(xsq, POLY_COEFFS[0], POLY_COEFFS[1], POLY_COEFFS[2],
+ POLY_COEFFS[3], POLY_COEFFS[4], POLY_COEFFS[5],
+ POLY_COEFFS[6], POLY_COEFFS[7], POLY_COEFFS[9],
+ POLY_COEFFS[9]);
+ };
+
+ // if |x| <= 0.5:
+ if (x_abs <= 0x3800) {
+ // Use polynomial approximation of asin(x)/pi in the range [0, 0.5]
+ float16 xsq = x * x;
+ float16 result = x * __asinpi_polyeval(xsq);
+ return fputil::cast<float16>(result);
+ }
+
+ // If |x| > 0.5, we need to use the range reduction method:
+ // y = asin(x) => x = sin(y)
+ // because: sin(a) = cos(pi/2 - a)
+ // therefore:
+ // x = cos(pi/2 - y)
+ // let z = pi/2 - y,
+ // x = cos(z)
+ // becuase: cos(2a) = 1 - 2 * sin^2(a), z = 2a, a = z/2
+ // therefore:
+ // cos(z) = 1 - 2 * sin^2(z/2)
+ // sin(z/2) = sqrt((1 - cos(z))/2)
+ // sin(z/2) = sqrt((1 - x)/2)
+ // let u = (1 - x)/2
+ // then:
+ // sin(z/2) = sqrt(u)
+ // z/2 = asin(sqrt(u))
+ // z = 2 * asin(sqrt(u))
+ // pi/2 - y = 2 * asin(sqrt(u))
+ // y = pi/2 - 2 * asin(sqrt(u))
+ // y/pi = 1/2 - 2 * asin(sqrt(u))/pi
+ //
+ // Finally, we can write:
+ // asinpi(x) = 1/2 - 2 * asinpi(sqrt(u))
+
+ float16 u = fputil::multiply_add(-ONE_OVER_TWO, x, ONE_OVER_TWO);
+
+ float16 asinpi_sqrt_u = __asinpi_polyeval(u);
+
+ float16 result = fputil::multiply_add(-2.0f16, asinpi_sqrt_u, ONE_OVER_TWO);
+
+ return fputil::cast<float16>(result);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
>From 813f341c3efa799fa310d8ff17d0c84323434b57 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Fri, 27 Jun 2025 22:40:29 +0300
Subject: [PATCH 02/19] formatting
---
libc/src/math/generic/asinpif16.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp
index 7de675211e5d2..facb06b540644 100644
--- a/libc/src/math/generic/asinpif16.cpp
+++ b/libc/src/math/generic/asinpif16.cpp
@@ -180,9 +180,7 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
// asinpi(x) = 1/2 - 2 * asinpi(sqrt(u))
float16 u = fputil::multiply_add(-ONE_OVER_TWO, x, ONE_OVER_TWO);
-
float16 asinpi_sqrt_u = __asinpi_polyeval(u);
-
float16 result = fputil::multiply_add(-2.0f16, asinpi_sqrt_u, ONE_OVER_TWO);
return fputil::cast<float16>(result);
>From 69e654e4657283b8dd7123b781953909cc14b66c Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Fri, 27 Jun 2025 22:46:14 +0300
Subject: [PATCH 03/19] builld: add missed entrypoint
---
libc/src/math/CMakeLists.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt
index d177ff79141c0..e7ccb3726c54c 100644
--- a/libc/src/math/CMakeLists.txt
+++ b/libc/src/math/CMakeLists.txt
@@ -56,6 +56,8 @@ add_math_entrypoint_object(asinh)
add_math_entrypoint_object(asinhf)
add_math_entrypoint_object(asinhf16)
+add_math_entrypoint_object(asinpif16)
+
add_math_entrypoint_object(atan)
add_math_entrypoint_object(atanf)
>From 453cf1850b70c49b297dab33548677e5fea1e20c Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Fri, 27 Jun 2025 22:46:33 +0300
Subject: [PATCH 04/19] test: add unit tests for `asinpif16`
---
libc/test/src/math/CMakeLists.txt | 11 ++
libc/test/src/math/asinpif16_test.cpp | 140 ++++++++++++++++++++++++++
2 files changed, 151 insertions(+)
create mode 100644 libc/test/src/math/asinpif16_test.cpp
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 7ee8b86135557..e6786a706eec9 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2245,6 +2245,17 @@ add_fp_unittest(
libc.src.math.asinf16
)
+add_fp_unittest(
+ asinfpi16_test
+ NEED_MPFR
+ SUITE
+ libc-math-unittests
+ SRCS
+ asinpif16_test.cpp
+ DEPENDS
+ libc.src.math.asinpif16
+)
+
add_fp_unittest(
acosf_test
NEED_MPFR
diff --git a/libc/test/src/math/asinpif16_test.cpp b/libc/test/src/math/asinpif16_test.cpp
new file mode 100644
index 0000000000000..ba01bc0119f0c
--- /dev/null
+++ b/libc/test/src/math/asinpif16_test.cpp
@@ -0,0 +1,140 @@
+//===-- Unittests for asinpif16 -------------------------------------------===//
+//
+// 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/errno/libc_errno.h"
+#include "src/math/asinpif16.h"
+#include "test/UnitTest/FPMatcher.h"
+
+#include <errno.h>
+#include <stdint.h>
+
+using LlvmLibcAsinpif16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
+
+TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) {
+ using FPBits = LIBC_NAMESPACE::fputil::FPBits<float16>;
+
+ // Test zero
+ EXPECT_FP_EQ(FPBits::zero(), LIBC_NAMESPACE::asinpif16(FPBits::zero()));
+ EXPECT_FP_EQ(FPBits::neg_zero(),
+ LIBC_NAMESPACE::asinpif16(FPBits::neg_zero()));
+
+ // Test +/-1
+ EXPECT_FP_EQ(float16(0.5), LIBC_NAMESPACE::asinpif16(float16(1.0)));
+ EXPECT_FP_EQ(float16(-0.5), LIBC_NAMESPACE::asinpif16(float16(-1.0)));
+
+ // Test NaN inputs
+ EXPECT_FP_EQ(FPBits::quiet_nan(),
+ LIBC_NAMESPACE::asinpif16(FPBits::quiet_nan()));
+ EXPECT_FP_EQ(FPBits::quiet_nan(),
+ LIBC_NAMESPACE::asinpif16(FPBits::signaling_nan()));
+
+ // Test infinity inputs - should return NaN and set errno
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(FPBits::inf()));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan(),
+ LIBC_NAMESPACE::asinpif16(FPBits::neg_inf()));
+ EXPECT_MATH_ERRNO(EDOM);
+}
+
+TEST_F(LlvmLibcAsinpif16Test, OutOfRange) {
+ using FPBits = LIBC_NAMESPACE::fputil::FPBits<float16>;
+
+ // Test values > 1
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(float16(1.5)));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(float16(2.0)));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ // Test values < -1
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(float16(-1.5)));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(float16(-2.0)));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ // Test maximum normal value (should be > 1 for float16)
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan(),
+ LIBC_NAMESPACE::asinpif16(FPBits::max_normal()));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan(),
+ LIBC_NAMESPACE::asinpif16(FPBits::max_normal().get_sign()));
+ EXPECT_MATH_ERRNO(EDOM);
+}
+
+TEST_F(LlvmLibcAsinpif16Test, SmallValues) {
+ using FPBits = LIBC_NAMESPACE::fputil::FPBits<float16>;
+
+ // Test very small values - should be close to x/π
+ constexpr float16 small_vals[] = {
+ 0x1.0p-10, // Small positive
+ -0x1.0p-10, // Small negative
+ 0x1.0p-14, // Very small positive
+ -0x1.0p-14, // Very small negative
+ };
+
+ for (float16 x : small_vals) {
+ float16 result = LIBC_NAMESPACE::asinpif16(x);
+ // For small x, asinpi(x) ≈ x/π ≈ 0.318309886 * x
+ // We expect the result to be close to x/π but not exactly due to polynomial
+ // approximation
+ EXPECT_TRUE(LIBC_NAMESPACE::fputil::abs(result) <=
+ LIBC_NAMESPACE::fputil::abs(x));
+ }
+
+ // Test minimum subnormal values
+ EXPECT_FP_EQ_ALL_ROUNDING(FPBits::min_subnormal(),
+ LIBC_NAMESPACE::asinpif16(FPBits::min_subnormal()));
+ EXPECT_FP_EQ_ALL_ROUNDING(
+ FPBits::min_subnormal().get_sign(),
+ LIBC_NAMESPACE::asinpif16(FPBits::min_subnormal().get_sign()));
+}
+
+
+TEST_F(LlvmLibcAsinpif16Test, SymmetryProperty) {
+ // Test that asinpi(-x) = -asinpi(x)
+ constexpr float16 test_vals[] = {0.1, 0.25, 0.5, 0.75, 0.9, 0.99, 1.0};
+
+ for (float16 x : test_vals) {
+ if (x <= 1.0) { // Only test valid domain
+ float16 pos_result = LIBC_NAMESPACE::asinpif16(x);
+ float16 neg_result = LIBC_NAMESPACE::asinpif16(-x);
+
+ EXPECT_FP_EQ(pos_result, -neg_result);
+ }
+ }
+}
+
+TEST_F(LlvmLibcAsinpif16Test, RangeValidation) {
+ // Test that output is always in [-0.5, 0.5] for valid inputs
+ constexpr int num_tests = 1000;
+
+ for (int i = 0; i <= num_tests; ++i) {
+ // Generate test value in [-1, 1]
+ float t = -1.0f + (2.0f * i) / num_tests;
+ float16 x = static_cast<float16>(t);
+
+ if (LIBC_NAMESPACE::fputil::abs(x) <= 1.0) {
+ float16 result = LIBC_NAMESPACE::asinpif16(x);
+
+ // Result should be in [-0.5, 0.5]
+ EXPECT_TRUE(result >= -0.5);
+ EXPECT_TRUE(result <= 0.5);
+ }
+ }
+}
\ No newline at end of file
>From 1897e003b564b6fbe6010719156bd11f5a536975 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 18:43:51 +0300
Subject: [PATCH 05/19] fix the typo in unittest build entry
---
libc/test/src/math/CMakeLists.txt | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index e6786a706eec9..bd62b76817ceb 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2246,14 +2246,16 @@ add_fp_unittest(
)
add_fp_unittest(
- asinfpi16_test
+ asinpif16_test
NEED_MPFR
SUITE
libc-math-unittests
SRCS
asinpif16_test.cpp
DEPENDS
- libc.src.math.asinpif16
+ libc.src.math.fabs
+ libc.src.math.asinpif16
+ libc.src.__support.FPUtil.fp_bits
)
add_fp_unittest(
>From a8122b77119ad5fa812ba884f525c21c98e16006 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 19:07:34 +0300
Subject: [PATCH 06/19] fix bugs
---
libc/src/math/generic/asinpif16.cpp | 98 +++++++++++++----------------
1 file changed, 43 insertions(+), 55 deletions(-)
diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp
index facb06b540644..34b0b7e7779fc 100644
--- a/libc/src/math/generic/asinpif16.cpp
+++ b/libc/src/math/generic/asinpif16.cpp
@@ -6,60 +6,40 @@
//
//===----------------------------------------------------------------------===//
+#include "src/math/asinpif16.h"
#include "hdr/errno_macros.h"
#include "hdr/fenv_macros.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/except_value_utils.h"
#include "src/__support/FPUtil/multiply_add.h"
#include "src/__support/FPUtil/sqrt.h"
#include "src/__support/macros/optimization.h"
-#include "src/math/asinfpi16.h"
namespace LIBC_NAMESPACE_DECL {
-static constexpr float16 ONE_OVER_TWO = 0x3800; // 0.5f16
+static constexpr float16 ONE_OVER_TWO = 0.5f16;
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-static constexpr size_t N_ASINFPI_EXCEPTS = 9;
-
-static constexpr float16 ONE_OVER_THREE = 0x3555; // 0.333251953125f16
-static constexpr float16 ONE_OVER_FOUR = 0x3400; // 0.25f16
-static constexpr float16 ONE_OVER_SIX = 0x32ab; // 0.166748046875f16
+static constexpr size_t N_ASINFPI_EXCEPTS = 3;
+static constexpr float16 ONE_OVER_SIX = 0.166748046875f16;
static constexpr fputil::ExceptValues<float16, N_ASINFPI_EXCEPTS>
ASINFPI_EXCEPTS{{
// (input_hex, RZ_output_hex, RU_offset, RD_offset, RN_offset)
-
// x = 0.0, asinfpi(0.0) = 0.0
{0x0000, 0x0000, 0, 0, 0},
// x = 1.0, asinfpi(1.0) = 0.5
- {0x3C00, ONE_OVER_TWO.uintval(), 0, 0, 0},
-
- // x = -1.0, asinfpi(-1.0) = -0.5
- {0xBC00, (fputil::FPBits<float16>(-ONE_OVER_TWO)).uintval(), 0, 0, 0},
+ {(fputil::FPBits<float16>(1.0f16)).uintval(),
+ (fputil::FPBits<float16>(ONE_OVER_TWO)).uintval(), 0, 0, 0},
// x = 0.5, asinfpi(0.5) = 1/6
- {0x3800, ONE_OVER_SIX.uintval(), 0, 0, 0},
-
- // x = -0.5, asinfpi(-0.5) = -1/6
- {0xB800, (fputil::FPBits<float16>(-ONE_OVER_SIX)).uintval(), 0, 0, 0},
-
- // x = sqrt(2)/2 ~ 0.70710678, asinfpi(x) = 1/4
- // 0x3B41 is float16 for ~0.707. 0x3400 is float16 for 0.25
- {0x3B41, ONE_OVER_FOUR.uintval(), 0, 0, 0},
-
- // x = -sqrt(2)/2 ~ -0.70710678, asinfpi(x) = -1/4
- {0xBB41, (fputil::FPBits<float16>(-ONE_OVER_FOUR)).uintval(), 0, 0, 0},
-
- // x = sqrt(3)/2 ~ 0.8660254, asinfpi(x) = 1/3
- // 0x3BF2 is float16 for ~0.866. 0x3555 is float16 for 1/3
- {0x3BF2, ONE_OVER_THREE.uintval(), 0, 0, 0},
+ {(fputil::FPBits<float16>(0.5f16)).uintval(),
+ (fputil::FPBits<float16>(ONE_OVER_SIX)).uintval(), 0, 0, 0},
- // x = -sqrt(3)/2 ~ -0.8660254, asinfpi(x) = -1/3
- {0xBBF2, (fputil::FPBits<float16>(-ONE_OVER_THREE)).uintval(), 0, 0, 0},
}};
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
@@ -68,10 +48,14 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
FPBits xbits(x);
uint16_t x_uint = xbits.uintval();
- uint16_t x_abs = xbits.uintval() & 0x7fffU;
- uint16_t x_sign = x_uint >> 15;
+ bool is_neg = static_cast<bool>(x_uint >> 15);
+ float16 x_abs = is_neg ? -x : x;
- if (LIBC_UNLIKELY(x_abs > 0x3c00)) {
+ auto __signed_result = [is_neg](float16 r) -> float16 {
+ return is_neg ? -r : r;
+ };
+
+ if (LIBC_UNLIKELY(x_abs > 1.0f16)) {
// aspinf16(NaN) = NaN
if (xbits.is_nan()) {
if (xbits.is_signaling_nan()) {
@@ -89,31 +73,31 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
}
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- // Handle exceptional values
- if (auto r = ACOSF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value()))
- return r.value();
-
-#else
- // Handling zero
- if (LIBC_UNLIKELY(x_abs == 0x0000)) {
- return x;
+ // exceptional values
+ if (auto r = ASINFPI_EXCEPTS.lookup(x_uint); LIBC_UNLIKELY(r.has_value())) {
+ return (r.value());
+ }
+#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
+
+ // zero
+ if (LIBC_UNLIKELY(x_abs == 0.0f16)) {
+ return 0.0f16;
}
- // Handling +/-1.0
- // If x is +/-1.0, return +/-0.5
- if (LIBC_UNLIKELY(x_abs == 0x3c00)) {
- return fputil::cast<float16>(x_sign ? -ONE_OVER_TWO : ONE_OVER_TWO);
+ // +/-1.0
+ // if x is +/-1.0, return +/-0.5
+ if (LIBC_UNLIKELY(x_abs == 1.0f16)) {
+ return fputil::cast<float16>(__signed_result(ONE_OVER_TWO));
}
-#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
// the coefficients for the polynomial approximation of asin(x)/pi in the
// range [0, 0.5] extracted using python-sympy
//
// Python code to generate the coefficients:
- // from sympy import *
- // import math
- // x = symbols('x')
- // print(series(asin(x)/math.pi, x, 0, 21))
+ // > from sympy import *
+ // > import math
+ // > x = symbols('x')
+ // > print(series(asin(x)/math.pi, x, 0, 21))
//
// OUTPUT:
//
@@ -143,16 +127,16 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
auto __asinpi_polyeval = [](float16 xsq) -> float16 {
return fputil::polyeval(xsq, POLY_COEFFS[0], POLY_COEFFS[1], POLY_COEFFS[2],
POLY_COEFFS[3], POLY_COEFFS[4], POLY_COEFFS[5],
- POLY_COEFFS[6], POLY_COEFFS[7], POLY_COEFFS[9],
+ POLY_COEFFS[6], POLY_COEFFS[7], POLY_COEFFS[8],
POLY_COEFFS[9]);
};
// if |x| <= 0.5:
- if (x_abs <= 0x3800) {
+ if (LIBC_UNLIKELY(x_abs <= ONE_OVER_TWO)) {
// Use polynomial approximation of asin(x)/pi in the range [0, 0.5]
float16 xsq = x * x;
float16 result = x * __asinpi_polyeval(xsq);
- return fputil::cast<float16>(result);
+ return fputil::cast<float16>(__signed_result(result));
}
// If |x| > 0.5, we need to use the range reduction method:
@@ -178,12 +162,16 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
//
// Finally, we can write:
// asinpi(x) = 1/2 - 2 * asinpi(sqrt(u))
+ // where u = (1 - x) /2
+ // = 0.5 - 0.5 * x
+ // = multiply_add(-0.5, x, 0.5)
- float16 u = fputil::multiply_add(-ONE_OVER_TWO, x, ONE_OVER_TWO);
- float16 asinpi_sqrt_u = __asinpi_polyeval(u);
+ float16 u = fputil::multiply_add(-ONE_OVER_TWO, x_abs, ONE_OVER_TWO);
+ float16 u_sqrt = fputil::sqrt<float16>(u);
+ float16 asinpi_sqrt_u = u_sqrt * __asinpi_polyeval(u);
float16 result = fputil::multiply_add(-2.0f16, asinpi_sqrt_u, ONE_OVER_TWO);
- return fputil::cast<float16>(result);
+ return fputil::cast<float16>(__signed_result(result));
}
} // namespace LIBC_NAMESPACE_DECL
>From 50f9029c0945379a2e788135a184639cd0d66d83 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 19:07:45 +0300
Subject: [PATCH 07/19] fix the test
---
libc/test/src/math/asinpif16_test.cpp | 102 +++++++++-----------------
1 file changed, 36 insertions(+), 66 deletions(-)
diff --git a/libc/test/src/math/asinpif16_test.cpp b/libc/test/src/math/asinpif16_test.cpp
index ba01bc0119f0c..6d8f76568902e 100644
--- a/libc/test/src/math/asinpif16_test.cpp
+++ b/libc/test/src/math/asinpif16_test.cpp
@@ -8,6 +8,7 @@
#include "src/errno/libc_errno.h"
#include "src/math/asinpif16.h"
+#include "src/math/fabs.h"
#include "test/UnitTest/FPMatcher.h"
#include <errno.h>
@@ -18,29 +19,28 @@ using LlvmLibcAsinpif16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) {
using FPBits = LIBC_NAMESPACE::fputil::FPBits<float16>;
- // Test zero
- EXPECT_FP_EQ(FPBits::zero(), LIBC_NAMESPACE::asinpif16(FPBits::zero()));
- EXPECT_FP_EQ(FPBits::neg_zero(),
- LIBC_NAMESPACE::asinpif16(FPBits::neg_zero()));
+ // zero
+ EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::asinpif16(0.0f16));
- // Test +/-1
+ // +/-1
EXPECT_FP_EQ(float16(0.5), LIBC_NAMESPACE::asinpif16(float16(1.0)));
EXPECT_FP_EQ(float16(-0.5), LIBC_NAMESPACE::asinpif16(float16(-1.0)));
- // Test NaN inputs
- EXPECT_FP_EQ(FPBits::quiet_nan(),
- LIBC_NAMESPACE::asinpif16(FPBits::quiet_nan()));
- EXPECT_FP_EQ(FPBits::quiet_nan(),
- LIBC_NAMESPACE::asinpif16(FPBits::signaling_nan()));
+ // NaN inputs
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(FPBits::quiet_nan().get_val()));
- // Test infinity inputs - should return NaN and set errno
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(FPBits::signaling_nan().get_val()));
+
+ // infinity inputs -> should return NaN
errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(FPBits::inf()));
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), LIBC_NAMESPACE::asinpif16(inf));
EXPECT_MATH_ERRNO(EDOM);
errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan(),
- LIBC_NAMESPACE::asinpif16(FPBits::neg_inf()));
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(neg_inf));
EXPECT_MATH_ERRNO(EDOM);
}
@@ -49,73 +49,44 @@ TEST_F(LlvmLibcAsinpif16Test, OutOfRange) {
// Test values > 1
errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(float16(1.5)));
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(float16(1.5)));
EXPECT_MATH_ERRNO(EDOM);
errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(float16(2.0)));
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(float16(2.0)));
EXPECT_MATH_ERRNO(EDOM);
// Test values < -1
errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(float16(-1.5)));
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(float16(-1.5)));
EXPECT_MATH_ERRNO(EDOM);
errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan(), LIBC_NAMESPACE::asinpif16(float16(-2.0)));
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(float16(-2.0)));
EXPECT_MATH_ERRNO(EDOM);
// Test maximum normal value (should be > 1 for float16)
errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan(),
- LIBC_NAMESPACE::asinpif16(FPBits::max_normal()));
- EXPECT_MATH_ERRNO(EDOM);
-
- errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan(),
- LIBC_NAMESPACE::asinpif16(FPBits::max_normal().get_sign()));
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(FPBits::max_normal().get_val()));
EXPECT_MATH_ERRNO(EDOM);
}
-TEST_F(LlvmLibcAsinpif16Test, SmallValues) {
- using FPBits = LIBC_NAMESPACE::fputil::FPBits<float16>;
-
- // Test very small values - should be close to x/π
- constexpr float16 small_vals[] = {
- 0x1.0p-10, // Small positive
- -0x1.0p-10, // Small negative
- 0x1.0p-14, // Very small positive
- -0x1.0p-14, // Very small negative
- };
-
- for (float16 x : small_vals) {
- float16 result = LIBC_NAMESPACE::asinpif16(x);
- // For small x, asinpi(x) ≈ x/π ≈ 0.318309886 * x
- // We expect the result to be close to x/π but not exactly due to polynomial
- // approximation
- EXPECT_TRUE(LIBC_NAMESPACE::fputil::abs(result) <=
- LIBC_NAMESPACE::fputil::abs(x));
- }
-
- // Test minimum subnormal values
- EXPECT_FP_EQ_ALL_ROUNDING(FPBits::min_subnormal(),
- LIBC_NAMESPACE::asinpif16(FPBits::min_subnormal()));
- EXPECT_FP_EQ_ALL_ROUNDING(
- FPBits::min_subnormal().get_sign(),
- LIBC_NAMESPACE::asinpif16(FPBits::min_subnormal().get_sign()));
-}
-
-
TEST_F(LlvmLibcAsinpif16Test, SymmetryProperty) {
// Test that asinpi(-x) = -asinpi(x)
- constexpr float16 test_vals[] = {0.1, 0.25, 0.5, 0.75, 0.9, 0.99, 1.0};
+ constexpr float16 test_vals[] = {0.1f16, 0.25f16, 0.5f16, 0.75f16,
+ 0.9f16, 0.99f16, 1.0f16};
for (float16 x : test_vals) {
- if (x <= 1.0) { // Only test valid domain
+ if (x <= 1.0) {
float16 pos_result = LIBC_NAMESPACE::asinpif16(x);
float16 neg_result = LIBC_NAMESPACE::asinpif16(-x);
- EXPECT_FP_EQ(pos_result, -neg_result);
+ EXPECT_FP_EQ(pos_result, LIBC_NAMESPACE::fabs(neg_result));
}
}
}
@@ -125,16 +96,15 @@ TEST_F(LlvmLibcAsinpif16Test, RangeValidation) {
constexpr int num_tests = 1000;
for (int i = 0; i <= num_tests; ++i) {
- // Generate test value in [-1, 1]
- float t = -1.0f + (2.0f * i) / num_tests;
- float16 x = static_cast<float16>(t);
+ float16 t = -1.0f16 + (2.0f16 * static_cast<float16>(i)) /
+ static_cast<float16>(num_tests);
- if (LIBC_NAMESPACE::fputil::abs(x) <= 1.0) {
- float16 result = LIBC_NAMESPACE::asinpif16(x);
+ if (LIBC_NAMESPACE::fabs(t) <= 1.0) {
+ float16 result = LIBC_NAMESPACE::asinpif16(t);
- // Result should be in [-0.5, 0.5]
- EXPECT_TRUE(result >= -0.5);
- EXPECT_TRUE(result <= 0.5);
+ // should be in [-0.5, 0.5]
+ EXPECT_TRUE(result >= -0.5f16);
+ EXPECT_TRUE(result <= 0.5f16);
}
}
-}
\ No newline at end of file
+}
>From 930f5be76abced4cf2762a32d23a99fdd105780e Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 19:41:29 +0300
Subject: [PATCH 08/19] remove unesseccery code
---
libc/src/math/generic/asinpif16.cpp | 12 +-----------
1 file changed, 1 insertion(+), 11 deletions(-)
diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp
index 34b0b7e7779fc..b66327c536f5f 100644
--- a/libc/src/math/generic/asinpif16.cpp
+++ b/libc/src/math/generic/asinpif16.cpp
@@ -79,17 +79,6 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
}
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
- // zero
- if (LIBC_UNLIKELY(x_abs == 0.0f16)) {
- return 0.0f16;
- }
-
- // +/-1.0
- // if x is +/-1.0, return +/-0.5
- if (LIBC_UNLIKELY(x_abs == 1.0f16)) {
- return fputil::cast<float16>(__signed_result(ONE_OVER_TWO));
- }
-
// the coefficients for the polynomial approximation of asin(x)/pi in the
// range [0, 0.5] extracted using python-sympy
//
@@ -101,6 +90,7 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
//
// OUTPUT:
//
+ //
// 0.318309886183791*x + 0.0530516476972984*x**3 + 0.0238732414637843*x**5 +
// 0.0142102627760621*x**7 + 0.00967087327815336*x**9 +
// 0.00712127941391293*x**11 + 0.00552355646848375*x**13 +
>From 3db1b0dcbd0fd2890d9ad12ea4842de6092dc867 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 20:06:35 +0300
Subject: [PATCH 09/19] add negatives for expected values
---
libc/src/math/generic/asinpif16.cpp | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp
index b66327c536f5f..fdcf8f78bb8d0 100644
--- a/libc/src/math/generic/asinpif16.cpp
+++ b/libc/src/math/generic/asinpif16.cpp
@@ -23,7 +23,7 @@ namespace LIBC_NAMESPACE_DECL {
static constexpr float16 ONE_OVER_TWO = 0.5f16;
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
-static constexpr size_t N_ASINFPI_EXCEPTS = 3;
+static constexpr size_t N_ASINFPI_EXCEPTS = 5;
static constexpr float16 ONE_OVER_SIX = 0.166748046875f16;
static constexpr fputil::ExceptValues<float16, N_ASINFPI_EXCEPTS>
@@ -32,14 +32,22 @@ static constexpr fputil::ExceptValues<float16, N_ASINFPI_EXCEPTS>
// x = 0.0, asinfpi(0.0) = 0.0
{0x0000, 0x0000, 0, 0, 0},
- // x = 1.0, asinfpi(1.0) = 0.5
- {(fputil::FPBits<float16>(1.0f16)).uintval(),
- (fputil::FPBits<float16>(ONE_OVER_TWO)).uintval(), 0, 0, 0},
+ // x = 1.0, asinfpi(1) = 1/2
+ {(fputil::FPBits<float16>(-1.0f16)).uintval(),
+ (fputil::FPBits<float16>(-ONE_OVER_TWO)).uintval(), 0, 0, 0},
+
+ // x = -1.0, asinfpi(-1.0) = -1/2
+ {(fputil::FPBits<float16>(-1.0f16)).uintval(),
+ (fputil::FPBits<float16>(-ONE_OVER_TWO)).uintval(), 0, 0, 0},
// x = 0.5, asinfpi(0.5) = 1/6
{(fputil::FPBits<float16>(0.5f16)).uintval(),
(fputil::FPBits<float16>(ONE_OVER_SIX)).uintval(), 0, 0, 0},
+ // x = -0.5, asinfpi(0.5) = -1/6
+ {(fputil::FPBits<float16>(-0.5f16)).uintval(),
+ (fputil::FPBits<float16>(-ONE_OVER_SIX)).uintval(), 0, 0, 0},
+
}};
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
@@ -75,7 +83,7 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
// exceptional values
if (auto r = ASINFPI_EXCEPTS.lookup(x_uint); LIBC_UNLIKELY(r.has_value())) {
- return (r.value());
+ return r.value();
}
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
@@ -90,7 +98,7 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
//
// OUTPUT:
//
- //
+ //
// 0.318309886183791*x + 0.0530516476972984*x**3 + 0.0238732414637843*x**5 +
// 0.0142102627760621*x**7 + 0.00967087327815336*x**9 +
// 0.00712127941391293*x**11 + 0.00552355646848375*x**13 +
>From 1097815848c58f49c6523a252d62eabcac23128c Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 20:06:52 +0300
Subject: [PATCH 10/19] remove unused headers
---
libc/test/src/math/asinpif16_test.cpp | 4 ----
1 file changed, 4 deletions(-)
diff --git a/libc/test/src/math/asinpif16_test.cpp b/libc/test/src/math/asinpif16_test.cpp
index 6d8f76568902e..7dad1b8fff3ed 100644
--- a/libc/test/src/math/asinpif16_test.cpp
+++ b/libc/test/src/math/asinpif16_test.cpp
@@ -6,14 +6,10 @@
//
//===----------------------------------------------------------------------===//
-#include "src/errno/libc_errno.h"
#include "src/math/asinpif16.h"
#include "src/math/fabs.h"
#include "test/UnitTest/FPMatcher.h"
-#include <errno.h>
-#include <stdint.h>
-
using LlvmLibcAsinpif16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) {
>From efa3207b799456c32b4971a628b6f167d824b0f2 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 20:09:13 +0300
Subject: [PATCH 11/19] fix formatting
---
libc/src/math/generic/asinpif16.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp
index fdcf8f78bb8d0..fdfb4484c9dfe 100644
--- a/libc/src/math/generic/asinpif16.cpp
+++ b/libc/src/math/generic/asinpif16.cpp
@@ -98,7 +98,6 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
//
// OUTPUT:
//
- //
// 0.318309886183791*x + 0.0530516476972984*x**3 + 0.0238732414637843*x**5 +
// 0.0142102627760621*x**7 + 0.00967087327815336*x**9 +
// 0.00712127941391293*x**11 + 0.00552355646848375*x**13 +
>From fae817a88fb287066b133b7d00cbef1673dbb4d8 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 23:42:30 +0300
Subject: [PATCH 12/19] revert the trailing space
---
libc/include/math.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/include/math.yaml b/libc/include/math.yaml
index d508c8bcdd7ed..07f6a46af5cae 100644
--- a/libc/include/math.yaml
+++ b/libc/include/math.yaml
@@ -84,7 +84,7 @@ functions:
- stdc
return_type: double
arguments:
- - type: double
+ - type: double
- name: asinpif16
standards:
- stdc
>From 58903b024a2c877b86ffab7f1775f637346ebb70 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 23:43:06 +0300
Subject: [PATCH 13/19] fix typos
---
libc/src/math/asinpif16.h | 4 ++--
libc/src/math/generic/asinpif16.cpp | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/libc/src/math/asinpif16.h b/libc/src/math/asinpif16.h
index 67ccb4ff4ac3d..b97166af63f5d 100644
--- a/libc/src/math/asinpif16.h
+++ b/libc/src/math/asinpif16.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_LIBC_SRC_MATH_ASINFPI16_H
-#define LLVM_LIBC_SRC_MATH_ASINFPI16_H
+#ifndef LLVM_LIBC_SRC_MATH_ASINPIF16_H
+#define LLVM_LIBC_SRC_MATH_ASINPIF16_H
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/types.h"
diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp
index fdfb4484c9dfe..b6cd49e58a140 100644
--- a/libc/src/math/generic/asinpif16.cpp
+++ b/libc/src/math/generic/asinpif16.cpp
@@ -1,4 +1,4 @@
-//===-- Half-precision asinf16(x) function --------------------------------===//
+//===-- Half-precision asinpif16(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.
>From 7a2b4afd9af6056a476b8422d70ffa9f9e13ab97 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 23:43:21 +0300
Subject: [PATCH 14/19] renaming lambdas
---
libc/src/math/generic/asinpif16.cpp | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp
index b6cd49e58a140..a3c3fe8c3f9e0 100644
--- a/libc/src/math/generic/asinpif16.cpp
+++ b/libc/src/math/generic/asinpif16.cpp
@@ -59,7 +59,7 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
bool is_neg = static_cast<bool>(x_uint >> 15);
float16 x_abs = is_neg ? -x : x;
- auto __signed_result = [is_neg](float16 r) -> float16 {
+ auto signed_result = [is_neg](float16 r) -> float16 {
return is_neg ? -r : r;
};
@@ -82,9 +82,8 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS
// exceptional values
- if (auto r = ASINFPI_EXCEPTS.lookup(x_uint); LIBC_UNLIKELY(r.has_value())) {
+ if (auto r = ASINFPI_EXCEPTS.lookup(x_uint); LIBC_UNLIKELY(r.has_value()))
return r.value();
- }
#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS
// the coefficients for the polynomial approximation of asin(x)/pi in the
@@ -121,7 +120,7 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
// polynomial evaluation using horner's method
// work only for |x| in [0, 0.5]
- auto __asinpi_polyeval = [](float16 xsq) -> float16 {
+ auto asinpi_polyeval = [](float16 xsq) -> float16 {
return fputil::polyeval(xsq, POLY_COEFFS[0], POLY_COEFFS[1], POLY_COEFFS[2],
POLY_COEFFS[3], POLY_COEFFS[4], POLY_COEFFS[5],
POLY_COEFFS[6], POLY_COEFFS[7], POLY_COEFFS[8],
@@ -132,8 +131,8 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
if (LIBC_UNLIKELY(x_abs <= ONE_OVER_TWO)) {
// Use polynomial approximation of asin(x)/pi in the range [0, 0.5]
float16 xsq = x * x;
- float16 result = x * __asinpi_polyeval(xsq);
- return fputil::cast<float16>(__signed_result(result));
+ float16 result = x * asinpi_polyeval(xsq);
+ return fputil::cast<float16>(signed_result(result));
}
// If |x| > 0.5, we need to use the range reduction method:
@@ -165,10 +164,10 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
float16 u = fputil::multiply_add(-ONE_OVER_TWO, x_abs, ONE_OVER_TWO);
float16 u_sqrt = fputil::sqrt<float16>(u);
- float16 asinpi_sqrt_u = u_sqrt * __asinpi_polyeval(u);
+ float16 asinpi_sqrt_u = u_sqrt * asinpi_polyeval(u);
float16 result = fputil::multiply_add(-2.0f16, asinpi_sqrt_u, ONE_OVER_TWO);
- return fputil::cast<float16>(__signed_result(result));
+ return fputil::cast<float16>(signed_result(result));
}
} // namespace LIBC_NAMESPACE_DECL
>From 30e4cc0d91cef7bdcdfff3b6009cbf90232e9346 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 23:43:42 +0300
Subject: [PATCH 15/19] missed build dependencies
---
libc/src/math/generic/CMakeLists.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt
index 1525c0fa032bf..ab72c8a47e811 100644
--- a/libc/src/math/generic/CMakeLists.txt
+++ b/libc/src/math/generic/CMakeLists.txt
@@ -4011,9 +4011,12 @@ add_entrypoint_object(
libc.hdr.errno_macros
libc.hdr.fenv_macros
libc.src.__support.FPUtil.cast
+ 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.FPUtil.polyeval
+ libc.src.__support.FPUtil.sqrt
libc.src.__support.macros.optimization
)
>From c20d7b162a7b9c7035c5114fe96f2db4c1db1c4b Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sat, 28 Jun 2025 23:53:28 +0300
Subject: [PATCH 16/19] fix warnings come fromm
`LlvmLibcAsinpif16Test.SymmetryProperty` test
---
libc/test/src/math/asinpif16_test.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/libc/test/src/math/asinpif16_test.cpp b/libc/test/src/math/asinpif16_test.cpp
index 7dad1b8fff3ed..cfeff3640875c 100644
--- a/libc/test/src/math/asinpif16_test.cpp
+++ b/libc/test/src/math/asinpif16_test.cpp
@@ -82,7 +82,8 @@ TEST_F(LlvmLibcAsinpif16Test, SymmetryProperty) {
float16 pos_result = LIBC_NAMESPACE::asinpif16(x);
float16 neg_result = LIBC_NAMESPACE::asinpif16(-x);
- EXPECT_FP_EQ(pos_result, LIBC_NAMESPACE::fabs(neg_result));
+ EXPECT_FP_EQ(pos_result,
+ static_cast<float16>(LIBC_NAMESPACE::fabs(neg_result)));
}
}
}
>From 521296d14157f70186fd5d45a64d4e0209202ba3 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Sun, 29 Jun 2025 01:55:07 +0300
Subject: [PATCH 17/19] use higher-precision type for poly coeffs
---
libc/src/math/generic/asinpif16.cpp | 39 ++++++++++++++---------------
1 file changed, 19 insertions(+), 20 deletions(-)
diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp
index a3c3fe8c3f9e0..644210e993d71 100644
--- a/libc/src/math/generic/asinpif16.cpp
+++ b/libc/src/math/generic/asinpif16.cpp
@@ -59,9 +59,7 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
bool is_neg = static_cast<bool>(x_uint >> 15);
float16 x_abs = is_neg ? -x : x;
- auto signed_result = [is_neg](float16 r) -> float16 {
- return is_neg ? -r : r;
- };
+ auto signed_result = [is_neg](auto r) -> auto { return is_neg ? -r : r; };
if (LIBC_UNLIKELY(x_abs > 1.0f16)) {
// aspinf16(NaN) = NaN
@@ -105,22 +103,22 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
//
// it's very accurate in the range [0, 0.5] and has a maximum error of
// 0.0000000000000001 in the range [0, 0.5].
- static constexpr float16 POLY_COEFFS[10] = {
- 0.318309886183791f16, // x^1
- 0.0530516476972984f16, // x^3
- 0.0238732414637843f16, // x^5
- 0.0142102627760621f16, // x^7
- 0.00967087327815336f16, // x^9
- 0.00712127941391293f16, // x^11
- 0.00552355646848375f16, // x^13
- 0.00444514782463692f16, // x^15
- 0.00367705242846804f16, // x^17
- 0.00310721681820837f16 // x^19
+ static constexpr float POLY_COEFFS[10] = {
+ 0.318309886183791f, // x^1
+ 0.0530516476972984f, // x^3
+ 0.0238732414637843f, // x^5
+ 0.0142102627760621f, // x^7
+ 0.00967087327815336f, // x^9
+ 0.00712127941391293f, // x^11
+ 0.00552355646848375f, // x^13
+ 0.00444514782463692f, // x^15
+ 0.00367705242846804f, // x^17
+ 0.00310721681820837f // x^19
};
// polynomial evaluation using horner's method
// work only for |x| in [0, 0.5]
- auto asinpi_polyeval = [](float16 xsq) -> float16 {
+ auto asinpi_polyeval = [](float xsq) -> float {
return fputil::polyeval(xsq, POLY_COEFFS[0], POLY_COEFFS[1], POLY_COEFFS[2],
POLY_COEFFS[3], POLY_COEFFS[4], POLY_COEFFS[5],
POLY_COEFFS[6], POLY_COEFFS[7], POLY_COEFFS[8],
@@ -131,7 +129,7 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
if (LIBC_UNLIKELY(x_abs <= ONE_OVER_TWO)) {
// Use polynomial approximation of asin(x)/pi in the range [0, 0.5]
float16 xsq = x * x;
- float16 result = x * asinpi_polyeval(xsq);
+ float result = x * asinpi_polyeval(xsq);
return fputil::cast<float16>(signed_result(result));
}
@@ -162,10 +160,11 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) {
// = 0.5 - 0.5 * x
// = multiply_add(-0.5, x, 0.5)
- float16 u = fputil::multiply_add(-ONE_OVER_TWO, x_abs, ONE_OVER_TWO);
- float16 u_sqrt = fputil::sqrt<float16>(u);
- float16 asinpi_sqrt_u = u_sqrt * asinpi_polyeval(u);
- float16 result = fputil::multiply_add(-2.0f16, asinpi_sqrt_u, ONE_OVER_TWO);
+ float u = static_cast<float>(
+ fputil::multiply_add(-ONE_OVER_TWO, x_abs, ONE_OVER_TWO));
+ float u_sqrt = fputil::sqrt<float>(static_cast<float>(u));
+ float asinpi_sqrt_u = u_sqrt * asinpi_polyeval(u);
+ float result = fputil::multiply_add(-2.0f16, asinpi_sqrt_u, ONE_OVER_TWO);
return fputil::cast<float16>(signed_result(result));
}
>From bf172b185d56a080e948fccac0d0fa3245528e94 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Mon, 30 Jun 2025 07:14:29 +0300
Subject: [PATCH 18/19] make an exhaustive test for `asinpif16`
---
libc/test/src/math/CMakeLists.txt | 2 -
libc/test/src/math/asinpif16_test.cpp | 111 ++++++--------------------
libc/utils/MPFRWrapper/MPCommon.cpp | 6 ++
libc/utils/MPFRWrapper/MPCommon.h | 1 +
libc/utils/MPFRWrapper/MPFRUtils.cpp | 2 +
libc/utils/MPFRWrapper/MPFRUtils.h | 1 +
6 files changed, 34 insertions(+), 89 deletions(-)
diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 3b95d7bc8c035..2a35243d63ab0 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -2275,9 +2275,7 @@ add_fp_unittest(
SRCS
asinpif16_test.cpp
DEPENDS
- libc.src.math.fabs
libc.src.math.asinpif16
- libc.src.__support.FPUtil.fp_bits
)
add_fp_unittest(
diff --git a/libc/test/src/math/asinpif16_test.cpp b/libc/test/src/math/asinpif16_test.cpp
index cfeff3640875c..8da9f45d5535b 100644
--- a/libc/test/src/math/asinpif16_test.cpp
+++ b/libc/test/src/math/asinpif16_test.cpp
@@ -1,4 +1,4 @@
-//===-- Unittests for asinpif16 -------------------------------------------===//
+//===-- Exhaustive test for asinpif16 -------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -7,101 +7,38 @@
//===----------------------------------------------------------------------===//
#include "src/math/asinpif16.h"
-#include "src/math/fabs.h"
#include "test/UnitTest/FPMatcher.h"
+#include "test/UnitTest/Test.h"
+#include "utils/MPFRWrapper/MPFRUtils.h"
using LlvmLibcAsinpif16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
-TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) {
- using FPBits = LIBC_NAMESPACE::fputil::FPBits<float16>;
+namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
- // zero
- EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::asinpif16(0.0f16));
+// Range: [0, Inf]
+static constexpr uint16_t POS_START = 0x0000U;
+static constexpr uint16_t POS_STOP = 0x7c00U;
- // +/-1
- EXPECT_FP_EQ(float16(0.5), LIBC_NAMESPACE::asinpif16(float16(1.0)));
- EXPECT_FP_EQ(float16(-0.5), LIBC_NAMESPACE::asinpif16(float16(-1.0)));
+// Range: [-Inf, 0]
+static constexpr uint16_t NEG_START = 0x8000U;
+static constexpr uint16_t NEG_STOP = 0xfc00U;
- // NaN inputs
- EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
- LIBC_NAMESPACE::asinpif16(FPBits::quiet_nan().get_val()));
-
- EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
- LIBC_NAMESPACE::asinpif16(FPBits::signaling_nan().get_val()));
-
- // infinity inputs -> should return NaN
- errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), LIBC_NAMESPACE::asinpif16(inf));
- EXPECT_MATH_ERRNO(EDOM);
-
- errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
- LIBC_NAMESPACE::asinpif16(neg_inf));
- EXPECT_MATH_ERRNO(EDOM);
-}
-
-TEST_F(LlvmLibcAsinpif16Test, OutOfRange) {
- using FPBits = LIBC_NAMESPACE::fputil::FPBits<float16>;
-
- // Test values > 1
- errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
- LIBC_NAMESPACE::asinpif16(float16(1.5)));
- EXPECT_MATH_ERRNO(EDOM);
-
- errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
- LIBC_NAMESPACE::asinpif16(float16(2.0)));
- EXPECT_MATH_ERRNO(EDOM);
-
- // Test values < -1
- errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
- LIBC_NAMESPACE::asinpif16(float16(-1.5)));
- EXPECT_MATH_ERRNO(EDOM);
-
- errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
- LIBC_NAMESPACE::asinpif16(float16(-2.0)));
- EXPECT_MATH_ERRNO(EDOM);
-
- // Test maximum normal value (should be > 1 for float16)
- errno = 0;
- EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
- LIBC_NAMESPACE::asinpif16(FPBits::max_normal().get_val()));
- EXPECT_MATH_ERRNO(EDOM);
-}
-
-TEST_F(LlvmLibcAsinpif16Test, SymmetryProperty) {
- // Test that asinpi(-x) = -asinpi(x)
- constexpr float16 test_vals[] = {0.1f16, 0.25f16, 0.5f16, 0.75f16,
- 0.9f16, 0.99f16, 1.0f16};
-
- for (float16 x : test_vals) {
- if (x <= 1.0) {
- float16 pos_result = LIBC_NAMESPACE::asinpif16(x);
- float16 neg_result = LIBC_NAMESPACE::asinpif16(-x);
-
- EXPECT_FP_EQ(pos_result,
- static_cast<float16>(LIBC_NAMESPACE::fabs(neg_result)));
- }
+TEST_F(LlvmLibcAsinpif16Test, PositiveRange) {
+ for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinpi, x,
+ LIBC_NAMESPACE::asinpif16(x), 0.5);
+ break;
}
}
-TEST_F(LlvmLibcAsinpif16Test, RangeValidation) {
- // Test that output is always in [-0.5, 0.5] for valid inputs
- constexpr int num_tests = 1000;
-
- for (int i = 0; i <= num_tests; ++i) {
- float16 t = -1.0f16 + (2.0f16 * static_cast<float16>(i)) /
- static_cast<float16>(num_tests);
-
- if (LIBC_NAMESPACE::fabs(t) <= 1.0) {
- float16 result = LIBC_NAMESPACE::asinpif16(t);
-
- // should be in [-0.5, 0.5]
- EXPECT_TRUE(result >= -0.5f16);
- EXPECT_TRUE(result <= 0.5f16);
- }
+TEST_F(LlvmLibcAsinpif16Test, NegativeRange) {
+ int i = 0;
+ for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
+ float16 x = FPBits(v).get_val();
+ EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinpi, -x,
+ LIBC_NAMESPACE::asinpif16(-x), 0.5);
+ if (i++ == 10)
+ break;
}
}
diff --git a/libc/utils/MPFRWrapper/MPCommon.cpp b/libc/utils/MPFRWrapper/MPCommon.cpp
index ccd4d2d01a4e2..7dde0d09e6ff6 100644
--- a/libc/utils/MPFRWrapper/MPCommon.cpp
+++ b/libc/utils/MPFRWrapper/MPCommon.cpp
@@ -105,6 +105,12 @@ MPFRNumber MPFRNumber::asinh() const {
return result;
}
+MPFRNumber MPFRNumber::asinpi() const {
+ MPFRNumber result(*this);
+ mpfr_asinpi(result.value, value, mpfr_rounding);
+ return result;
+}
+
MPFRNumber MPFRNumber::atan() const {
MPFRNumber result(*this);
mpfr_atan(result.value, value, mpfr_rounding);
diff --git a/libc/utils/MPFRWrapper/MPCommon.h b/libc/utils/MPFRWrapper/MPCommon.h
index 99cb7ec66a2ca..51c971215cf8f 100644
--- a/libc/utils/MPFRWrapper/MPCommon.h
+++ b/libc/utils/MPFRWrapper/MPCommon.h
@@ -185,6 +185,7 @@ class MPFRNumber {
MPFRNumber add(const MPFRNumber &b) const;
MPFRNumber asin() const;
MPFRNumber asinh() const;
+ MPFRNumber asinpi() const;
MPFRNumber atan() const;
MPFRNumber atan2(const MPFRNumber &b);
MPFRNumber atanh() const;
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 8853f96ef8f92..c58aae75cc700 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -38,6 +38,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
return mpfrInput.asin();
case Operation::Asinh:
return mpfrInput.asinh();
+ case Operation::Asinpi:
+ return mpfrInput.asinpi();
case Operation::Atan:
return mpfrInput.atan();
case Operation::Atanh:
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h
index c77a6aa3adeae..3b2d010473f7b 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.h
+++ b/libc/utils/MPFRWrapper/MPFRUtils.h
@@ -31,6 +31,7 @@ enum class Operation : int {
Acospi,
Asin,
Asinh,
+ Asinpi,
Atan,
Atanh,
Cbrt,
>From 6b9534f5e0d453c39ff0f152917d7eea2e08d5a6 Mon Sep 17 00:00:00 2001
From: hulxv <hulxxv at gmail.com>
Date: Mon, 30 Jun 2025 07:14:43 +0300
Subject: [PATCH 19/19] move old test to smoke
---
libc/test/src/math/smoke/CMakeLists.txt | 13 +++
libc/test/src/math/smoke/asinpif16_test.cpp | 89 +++++++++++++++++++++
2 files changed, 102 insertions(+)
create mode 100644 libc/test/src/math/smoke/asinpif16_test.cpp
diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt
index 599939cbec4b5..51aaf0b0d9f0d 100644
--- a/libc/test/src/math/smoke/CMakeLists.txt
+++ b/libc/test/src/math/smoke/CMakeLists.txt
@@ -3982,6 +3982,19 @@ add_fp_unittest(
libc.src.math.asinhf16
)
+add_fp_unittest(
+ asinpif16_test
+ NEED_MPFR
+ SUITE
+ libc-math-unittests
+ SRCS
+ asinpif16_test.cpp
+ DEPENDS
+ libc.src.math.fabs
+ libc.src.math.asinpif16
+ libc.src.__support.FPUtil.fp_bits
+)
+
add_fp_unittest(
acoshf_test
SUITE
diff --git a/libc/test/src/math/smoke/asinpif16_test.cpp b/libc/test/src/math/smoke/asinpif16_test.cpp
new file mode 100644
index 0000000000000..4bf630168864e
--- /dev/null
+++ b/libc/test/src/math/smoke/asinpif16_test.cpp
@@ -0,0 +1,89 @@
+//===-- Unittests for asinpif16 -------------------------------------------===//
+//
+// 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/asinpif16.h"
+#include "src/math/fabs.h"
+#include "test/UnitTest/FPMatcher.h"
+
+using LlvmLibcAsinpif16Test = LIBC_NAMESPACE::testing::FPTest<float16>;
+
+TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) {
+ using FPBits = LIBC_NAMESPACE::fputil::FPBits<float16>;
+
+ // zero
+ EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::asinpif16(0.0f16));
+
+ // +/-1
+ EXPECT_FP_EQ(float16(0.5), LIBC_NAMESPACE::asinpif16(float16(1.0)));
+ EXPECT_FP_EQ(float16(-0.5), LIBC_NAMESPACE::asinpif16(float16(-1.0)));
+
+ // NaN inputs
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(FPBits::quiet_nan().get_val()));
+
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(FPBits::signaling_nan().get_val()));
+
+ // infinity inputs -> should return NaN
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), LIBC_NAMESPACE::asinpif16(inf));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(neg_inf));
+ EXPECT_MATH_ERRNO(EDOM);
+}
+
+TEST_F(LlvmLibcAsinpif16Test, OutOfRange) {
+ using FPBits = LIBC_NAMESPACE::fputil::FPBits<float16>;
+
+ // Test values > 1
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(float16(1.5)));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(float16(2.0)));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ // Test values < -1
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(float16(-1.5)));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(float16(-2.0)));
+ EXPECT_MATH_ERRNO(EDOM);
+
+ // Test maximum normal value (should be > 1 for float16)
+ errno = 0;
+ EXPECT_FP_EQ(FPBits::quiet_nan().get_val(),
+ LIBC_NAMESPACE::asinpif16(FPBits::max_normal().get_val()));
+ EXPECT_MATH_ERRNO(EDOM);
+}
+
+TEST_F(LlvmLibcAsinpif16Test, SymmetryProperty) {
+ // Test that asinpi(-x) = -asinpi(x)
+ constexpr float16 test_vals[] = {0.1f16, 0.25f16, 0.5f16, 0.75f16,
+ 0.9f16, 0.99f16, 1.0f16};
+
+ for (float16 x : test_vals) {
+ if (x <= 1.0) {
+ float16 pos_result = LIBC_NAMESPACE::asinpif16(x);
+ float16 neg_result = LIBC_NAMESPACE::asinpif16(-x);
+
+ EXPECT_FP_EQ(pos_result,
+ static_cast<float16>(LIBC_NAMESPACE::fabs(neg_result)));
+ }
+ }
+}
More information about the libc-commits
mailing list