75 changes: 75 additions & 0 deletions libc/test/src/math/acosf_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//===-- Unittests for acosf -----------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "src/__support/FPUtil/FPBits.h"
#include "src/math/acosf.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
#include "utils/UnitTest/FPMatcher.h"
#include "utils/UnitTest/Test.h"
#include <math.h>

#include <errno.h>
#include <stdint.h>

using FPBits = __llvm_libc::fputil::FPBits<float>;

namespace mpfr = __llvm_libc::testing::mpfr;

DECLARE_SPECIAL_CONSTANTS(float)

TEST(LlvmLibcAcosfTest, SpecialNumbers) {
errno = 0;

EXPECT_FP_EQ(aNaN, __llvm_libc::acosf(aNaN));
EXPECT_MATH_ERRNO(0);

EXPECT_FP_EQ(aNaN, __llvm_libc::acosf(inf));
EXPECT_MATH_ERRNO(EDOM);

EXPECT_FP_EQ(aNaN, __llvm_libc::acosf(neg_inf));
EXPECT_MATH_ERRNO(EDOM);
}

TEST(LlvmLibcAcosfTest, InFloatRange) {
constexpr uint32_t COUNT = 1000000;
constexpr uint32_t STEP = UINT32_MAX / COUNT;
for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
float x = float(FPBits(v));
if (isnan(x) || isinf(x))
continue;
ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acos, x,
__llvm_libc::acosf(x), 0.5);
}
}

TEST(LlvmLibcAcosfTest, SpecificBitPatterns) {
constexpr int N = 13;
constexpr uint32_t INPUTS[N] = {
0x3f000000, // x = 0.5f
0x3f3504f3, // x = sqrt(2)/2, FE_DOWNWARD
0x3f3504f4, // x = sqrt(2)/2, FE_UPWARD
0x3f5db3d7, // x = sqrt(3)/2, FE_DOWNWARD
0x3f5db3d8, // x = sqrt(3)/2, FE_UPWARD
0x3f800000, // x = 1.0f
0x40000000, // x = 2.0f
0x328885a3, // x = 0x1.110b46p-26
0x39826222, // x = 0x1.04c444p-12
0x3d09bf86, // x = 0x1.137f0cp-5f
0x3de5fa1e, // x = 0x1.cbf43cp-4f
0x3f083a1a, // x = 0x1.107434p-1f
0x3f7741b6, // x = 0x1.ee836cp-1f
};

for (int i = 0; i < N; ++i) {
float x = float(FPBits(INPUTS[i]));
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acos, x,
__llvm_libc::acosf(x), 0.5);
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Acos, -x,
__llvm_libc::acosf(-x), 0.5);
}
}
17 changes: 17 additions & 0 deletions libc/test/src/math/exhaustive/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,20 @@ add_fp_unittest(
LINK_LIBRARIES
-lpthread
)

add_fp_unittest(
acosf_test
NO_RUN_POSTBUILD
NEED_MPFR
SUITE
libc_math_exhaustive_tests
SRCS
acosf_test.cpp
DEPENDS
.exhaustive_test
libc.include.math
libc.src.math.acosf
libc.src.__support.FPUtil.fp_bits
LINK_LIBRARIES
-lpthread
)
76 changes: 76 additions & 0 deletions libc/test/src/math/exhaustive/acosf_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//===-- Exhaustive test for acosf -----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "exhaustive_test.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/math/acosf.h"
#include "utils/MPFRWrapper/MPFRUtils.h"

#include <thread>

using FPBits = __llvm_libc::fputil::FPBits<float>;

namespace mpfr = __llvm_libc::testing::mpfr;

struct LlvmLibcAcosfExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
bool check(uint32_t start, uint32_t stop,
mpfr::RoundingMode rounding) override {
mpfr::ForceRoundingMode r(rounding);
uint32_t bits = start;
bool result = true;
do {
FPBits xbits(bits);
float x = float(xbits);
result &= EXPECT_MPFR_MATCH(mpfr::Operation::Acos, x,
__llvm_libc::acosf(x), 0.5, rounding);
} while (bits++ < stop);
return result;
}
};

static const int NUM_THREADS = std::thread::hardware_concurrency();

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

TEST_F(LlvmLibcAcosfExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Nearest);
}

TEST_F(LlvmLibcAcosfExhaustiveTest, PostiveRangeRoundUp) {
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Upward);
}

TEST_F(LlvmLibcAcosfExhaustiveTest, PostiveRangeRoundDown) {
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Downward);
}

TEST_F(LlvmLibcAcosfExhaustiveTest, PostiveRangeRoundTowardZero) {
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::TowardZero);
}

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

TEST_F(LlvmLibcAcosfExhaustiveTest, NegativeRangeRoundNearestTieToEven) {
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Nearest);
}

TEST_F(LlvmLibcAcosfExhaustiveTest, NegativeRangeRoundUp) {
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Upward);
}

TEST_F(LlvmLibcAcosfExhaustiveTest, NegativeRangeRoundDown) {
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Downward);
}

TEST_F(LlvmLibcAcosfExhaustiveTest, NegativeRangeRoundTowardZero) {
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::TowardZero);
}
3 changes: 1 addition & 2 deletions libc/test/src/math/exhaustive/asinf_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ static const int NUM_THREADS = std::thread::hardware_concurrency();
// Range: [0, Inf];
static const uint32_t POS_START = 0x0000'0000U;
static const uint32_t POS_STOP = 0x7f80'0000U;
/

TEST_F(LlvmLibcAsinfExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
TEST_F(LlvmLibcAsinfExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Nearest);
}

Expand Down
8 changes: 8 additions & 0 deletions libc/utils/MPFRWrapper/MPFRUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ class MPFRNumber {
return result;
}

MPFRNumber acos() const {
MPFRNumber result(*this);
mpfr_acos(result.value, value, mpfr_rounding);
return result;
}

MPFRNumber asin() const {
MPFRNumber result(*this);
mpfr_asin(result.value, value, mpfr_rounding);
Expand Down Expand Up @@ -526,6 +532,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
switch (op) {
case Operation::Abs:
return mpfrInput.abs();
case Operation::Acos:
return mpfrInput.acos();
case Operation::Asin:
return mpfrInput.asin();
case Operation::Atan:
Expand Down
1 change: 1 addition & 0 deletions libc/utils/MPFRWrapper/MPFRUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum class Operation : int {
// and output floating point numbers are of the same kind.
BeginUnaryOperationsSingleOutput,
Abs,
Acos,
Asin,
Atan,
Atanh,
Expand Down