Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ if(LIBC_TYPES_HAS_FLOAT16)
list(APPEND TARGET_LIBM_ENTRYPOINTS
# math.h C23 _Float16 entrypoints
libc.src.math.acosf16
libc.src.math.acospif16
libc.src.math.acoshf16
libc.src.math.asinf16
libc.src.math.asinhf16
Expand Down
2 changes: 1 addition & 1 deletion libc/docs/headers/math/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ Higher Math Functions
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| acosh | |check| | | | |check| | | 7.12.5.1 | F.10.2.1 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| acospi | | | | | | 7.12.4.8 | F.10.1.8 |
| acospi | | | | |check| | | 7.12.4.8 | F.10.1.8 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
| asin | |check| | | | |check| | | 7.12.4.2 | F.10.1.2 |
+-----------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+
Expand Down
46 changes: 7 additions & 39 deletions libc/include/math.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ functions:
arguments:
- type: _Float16
guard: LIBC_TYPES_HAS_FLOAT16
- name: acoshf
standards:
- stdc
return_type: float
arguments:
- type: float
name: acoshf16
- name: acospif16
standards:
- stdc
return_type: _Float16
arguments:
- type: _Float16
guard: LIBC_TYPES_HAS_FLOAT16
- name: acoshf
standards:
- stdc
return_type: float
arguments:
- type: float
- name: asin
standards:
- stdc
Expand All @@ -59,13 +59,6 @@ functions:
return_type: float
arguments:
- type: float
- name: asinhf16
standards:
- stdc
return_type: _Float16
arguments:
- type: _Float16
guard: LIBC_TYPES_HAS_FLOAT16
- name: atan
standards:
- stdc
Expand Down Expand Up @@ -93,14 +86,6 @@ functions:
arguments:
- type: long double
- type: long double
- name: atan2f128
standards:
- stdc
return_type: float128
arguments:
- type: float128
- type: float128
guard: LIBC_TYPES_HAS_FLOAT128
- name: atanf
standards:
- stdc
Expand Down Expand Up @@ -764,15 +749,6 @@ functions:
- type: float
- type: float
- type: float
- name: fmaf16
standards:
- stdc
return_type: _Float16
arguments:
- type: _Float16
- type: _Float16
- type: _Float16
guard: LIBC_TYPES_HAS_FLOAT16
- name: fmax
standards:
- stdc
Expand Down Expand Up @@ -1403,14 +1379,6 @@ functions:
arguments:
- type: float
- type: float
- name: hypotf16
standards:
- stdc
return_type: _Float16
arguments:
- type: _Float16
- type: _Float16
guard: LIBC_TYPES_HAS_FLOAT16
- name: ilogb
standards:
- stdc
Expand Down
1 change: 1 addition & 0 deletions libc/src/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ endfunction()
add_math_entrypoint_object(acos)
add_math_entrypoint_object(acosf)
add_math_entrypoint_object(acosf16)
add_math_entrypoint_object(acospif16)

add_math_entrypoint_object(acosh)
add_math_entrypoint_object(acoshf)
Expand Down
21 changes: 21 additions & 0 deletions libc/src/math/acospif16.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//===-- Implementation header for acospif16 ---------------------*- 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_ACOSPIF16_H
#define LLVM_LIBC_SRC_MATH_ACOSPIF16_H

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

namespace LIBC_NAMESPACE_DECL {

float16 acospif16(float16 x);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_MATH_ACOSPIF16_H
19 changes: 19 additions & 0 deletions libc/src/math/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4112,6 +4112,25 @@ add_entrypoint_object(
libc.src.__support.macros.properties.types
)

add_entrypoint_object(
acospif16
SRCS
acospif16.cpp
HDRS
../acospif16.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.FPUtil.polyeval
libc.src.__support.FPUtil.sqrt
libc.src.__support.macros.optimization
libc.src.__support.macros.properties.types
)

add_header_library(
atan_utils
HDRS
Expand Down
135 changes: 135 additions & 0 deletions libc/src/math/generic/acospif16.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
//===-- Half-precision acospif16(x) function ------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception.
//
//
//===----------------------------------------------------------------------===//

#include "src/math/acospif16.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/multiply_add.h"
#include "src/__support/FPUtil/sqrt.h"
#include "src/__support/macros/optimization.h"

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(float16, acospif16, (float16 x)) {
using FPBits = fputil::FPBits<float16>;
FPBits xbits(x);

uint16_t x_u = xbits.uintval();
uint16_t x_abs = x_u & 0x7fff;
uint16_t x_sign = x_u >> 15;

// |x| > 0x1p0, |x| > 1, or x is NaN.
if (LIBC_UNLIKELY(x_abs > 0x3c00)) {
// acospif16(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();
}

// |x| == 0x1p0, x is 1 or -1
// if x is (-)1, return 1
// if x is (+)1, return 0
if (LIBC_UNLIKELY(x_abs == 0x3c00))
return fputil::cast<float16>(x_sign ? 1.0f : 0.0f);

float xf = x;
float xsq = xf * xf;

// Degree-6 minimax polynomial coefficients of asin(x) generated by Sollya
// with: > P = fpminimax(asin(x)/(pi * x), [|0, 2, 4, 6, 8|], [|SG...|], [0,
// 0.5]);
constexpr float POLY_COEFFS[5] = {0x1.45f308p-2f, 0x1.b2900cp-5f,
0x1.897e36p-6f, 0x1.9efafcp-7f,
0x1.06d884p-6f};
// |x| <= 0x1p-1, |x| <= 0.5
if (x_abs <= 0x3800) {
// if x is 0, return 0.5
if (LIBC_UNLIKELY(x_abs == 0))
return fputil::cast<float16>(0.5f);

// Note that: acos(x) = pi/2 + asin(-x) = pi/2 - asin(x), then
// acospi(x) = 0.5 - asin(x)/pi
float interm =
fputil::polyeval(xsq, POLY_COEFFS[0], POLY_COEFFS[1], POLY_COEFFS[2],
POLY_COEFFS[3], POLY_COEFFS[4]);

return fputil::cast<float16>(fputil::multiply_add(-xf, interm, 0.5f));
}

// When |x| > 0.5, assume that 0.5 < |x| <= 1
//
// Step-by-step range-reduction proof:
// 1: Let y = asin(x), such that, x = sin(y)
// 2: From complimentary angle identity:
// x = sin(y) = cos(pi/2 - y)
// 3: Let z = pi/2 - y, such that x = cos(z)
// 4: From double angle formula; cos(2A) = 1 - 2 * sin^2(A):
// z = 2A, z/2 = A
// cos(z) = 1 - 2 * sin^2(z/2)
// 5: Make sin(z/2) subject of the formula:
// sin(z/2) = sqrt((1 - cos(z))/2)
// 6: Recall [3]; x = cos(z). Therefore:
// sin(z/2) = sqrt((1 - x)/2)
// 7: Let u = (1 - x)/2
// 8: Therefore:
// asin(sqrt(u)) = z/2
// 2 * asin(sqrt(u)) = z
// 9: Recall [3]; z = pi/2 - y. Therefore:
// y = pi/2 - z
// y = pi/2 - 2 * asin(sqrt(u))
// 10: Recall [1], y = asin(x). Therefore:
// asin(x) = pi/2 - 2 * asin(sqrt(u))
// 11: Recall that: acos(x) = pi/2 + asin(-x) = pi/2 - asin(x)
// Therefore:
// acos(x) = pi/2 - (pi/2 - 2 * asin(sqrt(u)))
// acos(x) = 2 * asin(sqrt(u))
// acospi(x) = 2 * (asin(sqrt(u)) / pi)
//
// THE RANGE REDUCTION, HOW?
// 12: Recall [7], u = (1 - x)/2
// 13: Since 0.5 < x <= 1, therefore:
// 0 <= u <= 0.25 and 0 <= sqrt(u) <= 0.5
//
// Hence, we can reuse the same [0, 0.5] domain polynomial approximation for
// Step [11] as `sqrt(u)` is in range.
// When -1 < x <= -0.5, the identity:
// acos(x) = pi - acos(-x)
// acospi(x) = 1 - acos(-x)/pi
// allows us to compute for the negative x value (lhs)
// with a positive x value instead (rhs).

float xf_abs = (xf < 0 ? -xf : xf);
float u = fputil::multiply_add(-0.5f, xf_abs, 0.5f);
float sqrt_u = fputil::sqrt<float>(u);

float asin_sqrt_u =
sqrt_u * fputil::polyeval(u, POLY_COEFFS[0], POLY_COEFFS[1],
POLY_COEFFS[2], POLY_COEFFS[3], POLY_COEFFS[4]);

// Same as acos(x), but devided the expression with pi
return fputil::cast<float16>(
x_sign ? fputil::multiply_add(-2.0f, asin_sqrt_u, 1.0f)
: 2.0f * asin_sqrt_u);
}
} // namespace LIBC_NAMESPACE_DECL
11 changes: 11 additions & 0 deletions libc/test/src/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2269,6 +2269,17 @@ add_fp_unittest(
libc.src.math.acosf16
)

add_fp_unittest(
acospif16_test
NEED_MPFR
SUITE
libc-math-unittests
SRCS
acospif16_test.cpp
DEPENDS
libc.src.math.acospif16
)

add_fp_unittest(
atanf_test
NEED_MPFR
Expand Down
42 changes: 42 additions & 0 deletions libc/test/src/math/acospif16_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===-- Exhaustive test for acospif16 -------------------------------------===//
//
// 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/acospif16.h"
#include "test/UnitTest/FPMatcher.h"
#include "test/UnitTest/Test.h"
#include "utils/MPFRWrapper/MPFRUtils.h"

using LlvmLibcAcospif16Test = LIBC_NAMESPACE::testing::FPTest<float16>;

namespace mpfr = LIBC_NAMESPACE::testing::mpfr;

// Range: [0, Inf]
static constexpr uint16_t POS_START = 0x0000U;
static constexpr uint16_t POS_STOP = 0x7c00U;

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

TEST_F(LlvmLibcAcospif16Test, PositiveRange) {
for (uint16_t v = POS_START; v <= POS_STOP; ++v) {
float16 x = FPBits(v).get_val();

EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acospi, x,
LIBC_NAMESPACE::acospif16(x), 0.5);
}
}

TEST_F(LlvmLibcAcospif16Test, NegativeRange) {
for (uint16_t v = NEG_START; v <= NEG_STOP; ++v) {
float16 x = FPBits(v).get_val();

EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acospi, x,
LIBC_NAMESPACE::acospif16(x), 0.5);
}
}
11 changes: 11 additions & 0 deletions libc/test/src/math/smoke/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4040,6 +4040,17 @@ add_fp_unittest(
libc.src.math.acosf16
)

add_fp_unittest(
acospif16_test
SUITE
libc-math-smoke-tests
SRCS
acospif16_test.cpp
DEPENDS
libc.src.errno.errno
libc.src.math.acospif16
)

add_fp_unittest(
atanf_test
SUITE
Expand Down
Loading
Loading