From 790f1c42e74d1c2daf6133ec04ae542bcc00c2f6 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 27 Jun 2025 02:58:36 +0300 Subject: [PATCH 01/31] [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 + 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(-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(-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(-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(-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; + + 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(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(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(result); +} + +} // namespace LIBC_NAMESPACE_DECL From 813f341c3efa799fa310d8ff17d0c84323434b57 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 27 Jun 2025 22:40:29 +0300 Subject: [PATCH 02/31] 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(result); From 69e654e4657283b8dd7123b781953909cc14b66c Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 27 Jun 2025 22:46:14 +0300 Subject: [PATCH 03/31] 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 Date: Fri, 27 Jun 2025 22:46:33 +0300 Subject: [PATCH 04/31] 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 +#include + +using LlvmLibcAsinpif16Test = LIBC_NAMESPACE::testing::FPTest; + +TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) { + using FPBits = LIBC_NAMESPACE::fputil::FPBits; + + // 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; + + // 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; + + // 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(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 Date: Sat, 28 Jun 2025 18:43:51 +0300 Subject: [PATCH 05/31] 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 Date: Sat, 28 Jun 2025 19:07:34 +0300 Subject: [PATCH 06/31] 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 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(-ONE_OVER_TWO)).uintval(), 0, 0, 0}, + {(fputil::FPBits(1.0f16)).uintval(), + (fputil::FPBits(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(-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(-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(0.5f16)).uintval(), + (fputil::FPBits(ONE_OVER_SIX)).uintval(), 0, 0, 0}, - // x = -sqrt(3)/2 ~ -0.8660254, asinfpi(x) = -1/3 - {0xBBF2, (fputil::FPBits(-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(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(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(__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(result); + return fputil::cast(__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(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(result); + return fputil::cast(__signed_result(result)); } } // namespace LIBC_NAMESPACE_DECL From 50f9029c0945379a2e788135a184639cd0d66d83 Mon Sep 17 00:00:00 2001 From: hulxv Date: Sat, 28 Jun 2025 19:07:45 +0300 Subject: [PATCH 07/31] 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 @@ -18,29 +19,28 @@ using LlvmLibcAsinpif16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) { using FPBits = LIBC_NAMESPACE::fputil::FPBits; - // 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; - - // 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(t); + float16 t = -1.0f16 + (2.0f16 * static_cast(i)) / + static_cast(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 Date: Sat, 28 Jun 2025 19:41:29 +0300 Subject: [PATCH 08/31] 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(__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 Date: Sat, 28 Jun 2025 20:06:35 +0300 Subject: [PATCH 09/31] 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 @@ -32,14 +32,22 @@ static constexpr fputil::ExceptValues // x = 0.0, asinfpi(0.0) = 0.0 {0x0000, 0x0000, 0, 0, 0}, - // x = 1.0, asinfpi(1.0) = 0.5 - {(fputil::FPBits(1.0f16)).uintval(), - (fputil::FPBits(ONE_OVER_TWO)).uintval(), 0, 0, 0}, + // x = 1.0, asinfpi(1) = 1/2 + {(fputil::FPBits(-1.0f16)).uintval(), + (fputil::FPBits(-ONE_OVER_TWO)).uintval(), 0, 0, 0}, + + // x = -1.0, asinfpi(-1.0) = -1/2 + {(fputil::FPBits(-1.0f16)).uintval(), + (fputil::FPBits(-ONE_OVER_TWO)).uintval(), 0, 0, 0}, // x = 0.5, asinfpi(0.5) = 1/6 {(fputil::FPBits(0.5f16)).uintval(), (fputil::FPBits(ONE_OVER_SIX)).uintval(), 0, 0, 0}, + // x = -0.5, asinfpi(0.5) = -1/6 + {(fputil::FPBits(-0.5f16)).uintval(), + (fputil::FPBits(-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 Date: Sat, 28 Jun 2025 20:06:52 +0300 Subject: [PATCH 10/31] 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 -#include - using LlvmLibcAsinpif16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) { From efa3207b799456c32b4971a628b6f167d824b0f2 Mon Sep 17 00:00:00 2001 From: hulxv Date: Sat, 28 Jun 2025 20:09:13 +0300 Subject: [PATCH 11/31] 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 Date: Sat, 28 Jun 2025 23:42:30 +0300 Subject: [PATCH 12/31] 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 Date: Sat, 28 Jun 2025 23:43:06 +0300 Subject: [PATCH 13/31] 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 Date: Sat, 28 Jun 2025 23:43:21 +0300 Subject: [PATCH 14/31] 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(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(__signed_result(result)); + float16 result = x * asinpi_polyeval(xsq); + return fputil::cast(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(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(__signed_result(result)); + return fputil::cast(signed_result(result)); } } // namespace LIBC_NAMESPACE_DECL From 30e4cc0d91cef7bdcdfff3b6009cbf90232e9346 Mon Sep 17 00:00:00 2001 From: hulxv Date: Sat, 28 Jun 2025 23:43:42 +0300 Subject: [PATCH 15/31] 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 Date: Sat, 28 Jun 2025 23:53:28 +0300 Subject: [PATCH 16/31] 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(LIBC_NAMESPACE::fabs(neg_result))); } } } From 521296d14157f70186fd5d45a64d4e0209202ba3 Mon Sep 17 00:00:00 2001 From: hulxv Date: Sun, 29 Jun 2025 01:55:07 +0300 Subject: [PATCH 17/31] 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(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(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(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( + fputil::multiply_add(-ONE_OVER_TWO, x_abs, ONE_OVER_TWO)); + float u_sqrt = fputil::sqrt(static_cast(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(signed_result(result)); } From bf172b185d56a080e948fccac0d0fa3245528e94 Mon Sep 17 00:00:00 2001 From: hulxv Date: Mon, 30 Jun 2025 07:14:29 +0300 Subject: [PATCH 18/31] 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; -TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) { - using FPBits = LIBC_NAMESPACE::fputil::FPBits; +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; - - // 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(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(i)) / - static_cast(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 Date: Mon, 30 Jun 2025 07:14:43 +0300 Subject: [PATCH 19/31] 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; + +TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) { + using FPBits = LIBC_NAMESPACE::fputil::FPBits; + + // 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; + + // 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(LIBC_NAMESPACE::fabs(neg_result))); + } + } +} From 0e904c95e3ea84c676adbbd24c8aaeab4eba0a52 Mon Sep 17 00:00:00 2001 From: hulxv Date: Thu, 3 Jul 2025 01:29:15 +0300 Subject: [PATCH 20/31] remove debugging code --- 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 8da9f45d5535b..1632fb52398c5 100644 --- a/libc/test/src/math/asinpif16_test.cpp +++ b/libc/test/src/math/asinpif16_test.cpp @@ -28,17 +28,13 @@ TEST_F(LlvmLibcAsinpif16Test, PositiveRange) { 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, 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; } } From f08c4edcd61667cf348e7f0d3c75eaaa5e74dc98 Mon Sep 17 00:00:00 2001 From: hulxv Date: Sat, 5 Jul 2025 02:46:55 +0300 Subject: [PATCH 21/31] remove expected value of `x=+/-0.5` --- libc/src/math/generic/asinpif16.cpp | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp index 644210e993d71..a6c5246190bed 100644 --- a/libc/src/math/generic/asinpif16.cpp +++ b/libc/src/math/generic/asinpif16.cpp @@ -23,8 +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 = 5; -static constexpr float16 ONE_OVER_SIX = 0.166748046875f16; +static constexpr size_t N_ASINFPI_EXCEPTS = 3; static constexpr fputil::ExceptValues ASINFPI_EXCEPTS{{ @@ -33,21 +32,12 @@ static constexpr fputil::ExceptValues {0x0000, 0x0000, 0, 0, 0}, // x = 1.0, asinfpi(1) = 1/2 - {(fputil::FPBits(-1.0f16)).uintval(), - (fputil::FPBits(-ONE_OVER_TWO)).uintval(), 0, 0, 0}, + {(fputil::FPBits(1.0f16)).uintval(), + (fputil::FPBits(ONE_OVER_TWO)).uintval(), 0, 0, 0}, // x = -1.0, asinfpi(-1.0) = -1/2 {(fputil::FPBits(-1.0f16)).uintval(), (fputil::FPBits(-ONE_OVER_TWO)).uintval(), 0, 0, 0}, - - // x = 0.5, asinfpi(0.5) = 1/6 - {(fputil::FPBits(0.5f16)).uintval(), - (fputil::FPBits(ONE_OVER_SIX)).uintval(), 0, 0, 0}, - - // x = -0.5, asinfpi(0.5) = -1/6 - {(fputil::FPBits(-0.5f16)).uintval(), - (fputil::FPBits(-ONE_OVER_SIX)).uintval(), 0, 0, 0}, - }}; #endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS From 5ec14baa5b597a60d6cd541e17e2f8e0a74bfa4b Mon Sep 17 00:00:00 2001 From: hulxv Date: Sat, 5 Jul 2025 02:47:23 +0300 Subject: [PATCH 22/31] convert poly into double --- libc/src/math/generic/asinpif16.cpp | 37 +++++++++++++++-------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp index a6c5246190bed..4ea5219b4568b 100644 --- a/libc/src/math/generic/asinpif16.cpp +++ b/libc/src/math/generic/asinpif16.cpp @@ -93,22 +93,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 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 + static constexpr double POLY_COEFFS[10] = { + 0.318309886183791, // x^1 + 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 }; // polynomial evaluation using horner's method // work only for |x| in [0, 0.5] - auto asinpi_polyeval = [](float xsq) -> float { + auto asinpi_polyeval = [](double xsq) -> double { 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], @@ -118,8 +118,9 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) { // if |x| <= 0.5: 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; - float result = x * asinpi_polyeval(xsq); + double xd = static_cast(x); + double xsq = xd * xd; + double result = xd * asinpi_polyeval(xsq); return fputil::cast(signed_result(result)); } @@ -150,11 +151,11 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) { // = 0.5 - 0.5 * x // = multiply_add(-0.5, x, 0.5) - float u = static_cast( + double u = static_cast( fputil::multiply_add(-ONE_OVER_TWO, x_abs, ONE_OVER_TWO)); - float u_sqrt = fputil::sqrt(static_cast(u)); - float asinpi_sqrt_u = u_sqrt * asinpi_polyeval(u); - float result = fputil::multiply_add(-2.0f16, asinpi_sqrt_u, ONE_OVER_TWO); + double u_sqrt = fputil::sqrt(static_cast(u)); + double asinpi_sqrt_u = u_sqrt * asinpi_polyeval(u); + double result = fputil::multiply_add(-2.0f16, asinpi_sqrt_u, ONE_OVER_TWO); return fputil::cast(signed_result(result)); } From 8ef4c7fa146058e9587d3ce3b9cbcf6ebecb9db9 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 11 Jul 2025 01:25:00 +0300 Subject: [PATCH 23/31] use `libc_errno` instead of `errno` --- libc/test/src/math/smoke/asinpif16_test.cpp | 22 ++++++++------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/libc/test/src/math/smoke/asinpif16_test.cpp b/libc/test/src/math/smoke/asinpif16_test.cpp index 4bf630168864e..16fb1f2a18da1 100644 --- a/libc/test/src/math/smoke/asinpif16_test.cpp +++ b/libc/test/src/math/smoke/asinpif16_test.cpp @@ -5,7 +5,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// - +#include "src/__support/libc_errno.h" #include "src/math/asinpif16.h" #include "src/math/fabs.h" #include "test/UnitTest/FPMatcher.h" @@ -13,8 +13,6 @@ using LlvmLibcAsinpif16Test = LIBC_NAMESPACE::testing::FPTest; TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) { - using FPBits = LIBC_NAMESPACE::fputil::FPBits; - // zero EXPECT_FP_EQ(0.0f16, LIBC_NAMESPACE::asinpif16(0.0f16)); @@ -30,43 +28,41 @@ TEST_F(LlvmLibcAsinpif16Test, SpecialNumbers) { LIBC_NAMESPACE::asinpif16(FPBits::signaling_nan().get_val())); // infinity inputs -> should return NaN - errno = 0; + libc_errno = 0; EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), LIBC_NAMESPACE::asinpif16(inf)); EXPECT_MATH_ERRNO(EDOM); - errno = 0; + libc_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; - // Test values > 1 - errno = 0; + libc_errno = 0; EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), LIBC_NAMESPACE::asinpif16(float16(1.5))); EXPECT_MATH_ERRNO(EDOM); - errno = 0; + libc_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; + libc_errno = 0; EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), LIBC_NAMESPACE::asinpif16(float16(-1.5))); EXPECT_MATH_ERRNO(EDOM); - errno = 0; + libc_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; + libc_errno = 0; EXPECT_FP_EQ(FPBits::quiet_nan().get_val(), LIBC_NAMESPACE::asinpif16(FPBits::max_normal().get_val())); EXPECT_MATH_ERRNO(EDOM); @@ -78,12 +74,10 @@ TEST_F(LlvmLibcAsinpif16Test, SymmetryProperty) { 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(LIBC_NAMESPACE::fabs(neg_result))); - } } } From 442902ec49e576a1a51a81932b865dcaace7f572 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 11 Jul 2025 01:25:17 +0300 Subject: [PATCH 24/31] formatting cmakefiles --- libc/test/src/math/CMakeLists.txt | 2 +- libc/test/src/math/smoke/CMakeLists.txt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 2a35243d63ab0..20756f0a308df 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -2275,7 +2275,7 @@ add_fp_unittest( SRCS asinpif16_test.cpp DEPENDS - libc.src.math.asinpif16 + libc.src.math.asinpif16 ) add_fp_unittest( diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 51aaf0b0d9f0d..3e90ff4716239 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -3990,9 +3990,10 @@ add_fp_unittest( SRCS asinpif16_test.cpp DEPENDS - libc.src.math.fabs libc.src.math.asinpif16 - libc.src.__support.FPUtil.fp_bits + libc.src.errno.errno + libc.src.math.fabs + libc.src.__support.FPUtil.fp_bits ) add_fp_unittest( From 818188b98cb27abccdd65ba1f89fb25a9eab6ab1 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 11 Jul 2025 01:25:57 +0300 Subject: [PATCH 25/31] rename `*ASINFPI_EXPECTS` to `*ASINPIF16_EXPECTS` --- libc/src/math/generic/asinpif16.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp index 4ea5219b4568b..fdcda4105c5e9 100644 --- a/libc/src/math/generic/asinpif16.cpp +++ b/libc/src/math/generic/asinpif16.cpp @@ -23,10 +23,10 @@ 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_ASINPIF16_EXCEPTS = 3; -static constexpr fputil::ExceptValues - ASINFPI_EXCEPTS{{ +static constexpr fputil::ExceptValues + ASINPIF16_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}, @@ -70,7 +70,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())) + if (auto r = ASINPIF16_EXCEPTS.lookup(x_uint); LIBC_UNLIKELY(r.has_value())) return r.value(); #endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS From 6b803f9ff94f07a4abee5a1974906327ae7d4748 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 11 Jul 2025 10:35:01 +0300 Subject: [PATCH 26/31] fix the test --- libc/src/math/generic/asinpif16.cpp | 56 +++++++++++---------------- libc/test/src/math/asinpif16_test.cpp | 6 +-- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp index fdcda4105c5e9..1772e96c58848 100644 --- a/libc/src/math/generic/asinpif16.cpp +++ b/libc/src/math/generic/asinpif16.cpp @@ -20,8 +20,6 @@ namespace LIBC_NAMESPACE_DECL { -static constexpr float16 ONE_OVER_TWO = 0.5f16; - #ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS static constexpr size_t N_ASINPIF16_EXCEPTS = 3; @@ -31,14 +29,12 @@ static constexpr fputil::ExceptValues // x = 0.0, asinfpi(0.0) = 0.0 {0x0000, 0x0000, 0, 0, 0}, - // x = 1.0, asinfpi(1) = 1/2 - {(fputil::FPBits(1.0f16)).uintval(), - (fputil::FPBits(ONE_OVER_TWO)).uintval(), 0, 0, 0}, - - // x = -1.0, asinfpi(-1.0) = -1/2 - {(fputil::FPBits(-1.0f16)).uintval(), - (fputil::FPBits(-ONE_OVER_TWO)).uintval(), 0, 0, 0}, + // x = 0x1.004p-3, asinpif16(x) = 0x1.47p-5 (RZ) + {0x3001U, 0x291cU, 1U, 0U, 1U}, + // x = 0x1.0bp-1, asinpif16(x) = 0x1.658p-3 (RZ) + {0x382cU, 0x3196U, 1U, 0U, 0U}, }}; + #endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) { @@ -94,33 +90,27 @@ 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 double POLY_COEFFS[10] = { - 0.318309886183791, // x^1 - 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 + 0x1.45f306dc9c889p-2, // x^1 + 0x1.b2995e7b7b5fdp-5, // x^3 + 0x1.8723a1d588a36p-6, // x^5 + 0x1.d1a452f20430dp-7, // x^7 + 0x1.3ce52a3a09f61p-7, // x^9 + 0x1.d2b33e303d375p-8, // x^11 + 0x1.69fde663c674fp-8, // x^13 + 0x1.235134885f19bp-8, // x^15 }; - // polynomial evaluation using horner's method // work only for |x| in [0, 0.5] - auto asinpi_polyeval = [](double xsq) -> double { - 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], - POLY_COEFFS[9]); + auto asinpi_polyeval = [](double x) -> double { + return x * fputil::polyeval(x * x, POLY_COEFFS[0], POLY_COEFFS[1], + POLY_COEFFS[2], POLY_COEFFS[3], POLY_COEFFS[4], + POLY_COEFFS[5], POLY_COEFFS[6], POLY_COEFFS[7]); }; // if |x| <= 0.5: - if (LIBC_UNLIKELY(x_abs <= ONE_OVER_TWO)) { + if (LIBC_UNLIKELY(x_abs <= 0.5f16)) { // Use polynomial approximation of asin(x)/pi in the range [0, 0.5] - double xd = static_cast(x); - double xsq = xd * xd; - double result = xd * asinpi_polyeval(xsq); + double result = asinpi_polyeval(fputil::cast(x_abs)); return fputil::cast(signed_result(result)); } @@ -151,11 +141,9 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) { // = 0.5 - 0.5 * x // = multiply_add(-0.5, x, 0.5) - double u = static_cast( - fputil::multiply_add(-ONE_OVER_TWO, x_abs, ONE_OVER_TWO)); - double u_sqrt = fputil::sqrt(static_cast(u)); - double asinpi_sqrt_u = u_sqrt * asinpi_polyeval(u); - double result = fputil::multiply_add(-2.0f16, asinpi_sqrt_u, ONE_OVER_TWO); + double u = fputil::multiply_add(-0.5, fputil::cast(x_abs), 0.5); + double asinpi_sqrt_u = asinpi_polyeval(fputil::sqrt(u)); + double result = fputil::multiply_add(-2.0, asinpi_sqrt_u, 0.5); return fputil::cast(signed_result(result)); } diff --git a/libc/test/src/math/asinpif16_test.cpp b/libc/test/src/math/asinpif16_test.cpp index 1632fb52398c5..5af1df2f1157f 100644 --- a/libc/test/src/math/asinpif16_test.cpp +++ b/libc/test/src/math/asinpif16_test.cpp @@ -27,14 +27,14 @@ 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); + LIBC_NAMESPACE::asinpif16(x), 0.5f); } } TEST_F(LlvmLibcAsinpif16Test, NegativeRange) { 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); + EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Asinpi, x, + LIBC_NAMESPACE::asinpif16(x), 0.5); } } From cf02f7cc126170f03ee4824051b6b30b87c42506 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 11 Jul 2025 10:35:43 +0300 Subject: [PATCH 27/31] fix typo --- libc/src/math/generic/asinpif16.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp index 1772e96c58848..6c42d328faeed 100644 --- a/libc/src/math/generic/asinpif16.cpp +++ b/libc/src/math/generic/asinpif16.cpp @@ -121,7 +121,7 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) { // 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 + // because: 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) From 36ed377ca86acc115810e165c17059b37f3e83db Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 11 Jul 2025 10:40:36 +0300 Subject: [PATCH 28/31] uesless using `signed_result` in `[0,0.5]` --- libc/src/math/generic/asinpif16.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp index 6c42d328faeed..8f1595d7686b2 100644 --- a/libc/src/math/generic/asinpif16.cpp +++ b/libc/src/math/generic/asinpif16.cpp @@ -110,8 +110,8 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) { // if |x| <= 0.5: if (LIBC_UNLIKELY(x_abs <= 0.5f16)) { // Use polynomial approximation of asin(x)/pi in the range [0, 0.5] - double result = asinpi_polyeval(fputil::cast(x_abs)); - return fputil::cast(signed_result(result)); + double result = asinpi_polyeval(fputil::cast(x)); + return fputil::cast(result); } // If |x| > 0.5, we need to use the range reduction method: From fffbb28f95333c7871566c04b61dd299284fb3c9 Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 11 Jul 2025 10:56:29 +0300 Subject: [PATCH 29/31] formatting --- libc/test/src/math/smoke/asinpif16_test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libc/test/src/math/smoke/asinpif16_test.cpp b/libc/test/src/math/smoke/asinpif16_test.cpp index 16fb1f2a18da1..e297dd90b31a5 100644 --- a/libc/test/src/math/smoke/asinpif16_test.cpp +++ b/libc/test/src/math/smoke/asinpif16_test.cpp @@ -74,10 +74,10 @@ TEST_F(LlvmLibcAsinpif16Test, SymmetryProperty) { 0.9f16, 0.99f16, 1.0f16}; for (float16 x : test_vals) { - float16 pos_result = LIBC_NAMESPACE::asinpif16(x); - float16 neg_result = LIBC_NAMESPACE::asinpif16(-x); + float16 pos_result = LIBC_NAMESPACE::asinpif16(x); + float16 neg_result = LIBC_NAMESPACE::asinpif16(-x); - EXPECT_FP_EQ(pos_result, - static_cast(LIBC_NAMESPACE::fabs(neg_result))); + EXPECT_FP_EQ(pos_result, + static_cast(LIBC_NAMESPACE::fabs(neg_result))); } } From a9deb29ff00a7c99b61eb4b6a2b440612c4690df Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 11 Jul 2025 17:52:28 +0300 Subject: [PATCH 30/31] enhancements --- libc/src/math/generic/asinpif16.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libc/src/math/generic/asinpif16.cpp b/libc/src/math/generic/asinpif16.cpp index 8f1595d7686b2..5103a3cb793e9 100644 --- a/libc/src/math/generic/asinpif16.cpp +++ b/libc/src/math/generic/asinpif16.cpp @@ -42,8 +42,8 @@ LLVM_LIBC_FUNCTION(float16, asinpif16, (float16 x)) { FPBits xbits(x); uint16_t x_uint = xbits.uintval(); - bool is_neg = static_cast(x_uint >> 15); - float16 x_abs = is_neg ? -x : x; + bool is_neg = xbits.is_neg(); + float16 x_abs = xbits.abs().get_val(); auto signed_result = [is_neg](auto r) -> auto { return is_neg ? -r : r; }; @@ -89,7 +89,7 @@ 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 double POLY_COEFFS[10] = { + constexpr double POLY_COEFFS[10] = { 0x1.45f306dc9c889p-2, // x^1 0x1.b2995e7b7b5fdp-5, // x^3 0x1.8723a1d588a36p-6, // x^5 From fcc4f8a7b191da8a743e7ba738d5efbdba1369ec Mon Sep 17 00:00:00 2001 From: hulxv Date: Fri, 11 Jul 2025 18:01:29 +0300 Subject: [PATCH 31/31] use `double` ulp tolerance instead of `float` --- libc/test/src/math/asinpif16_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/test/src/math/asinpif16_test.cpp b/libc/test/src/math/asinpif16_test.cpp index 5af1df2f1157f..3718f39fd06a6 100644 --- a/libc/test/src/math/asinpif16_test.cpp +++ b/libc/test/src/math/asinpif16_test.cpp @@ -27,7 +27,7 @@ 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.5f); + LIBC_NAMESPACE::asinpif16(x), 0.5); } }