65 changes: 65 additions & 0 deletions libc/test/src/math/atanf_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===-- Unittests for atanf -----------------------------------------------===//
//
// 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/atanf.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>

#include <initializer_list>

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

namespace mpfr = __llvm_libc::testing::mpfr;

DECLARE_SPECIAL_CONSTANTS(float)

TEST(LlvmLibcAtanfTest, SpecialNumbers) {
errno = 0;
__llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ(aNaN, __llvm_libc::atanf(aNaN));
EXPECT_FP_EXCEPTION(FE_INVALID);
EXPECT_MATH_ERRNO(0);

__llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ(0.0f, __llvm_libc::atanf(0.0f));
EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);

__llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
EXPECT_FP_EQ(-0.0f, __llvm_libc::atanf(-0.0f));
EXPECT_FP_EXCEPTION(0);
EXPECT_MATH_ERRNO(0);
}

TEST(LlvmLibcAtanfTest, InFloatRange) {
constexpr uint32_t COUNT = 1000000;
const uint32_t STEP = FPBits(inf).uintval() / COUNT;
for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
float x = float(FPBits(v));
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, x,
__llvm_libc::atanf(x), 0.5);
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, -x,
__llvm_libc::atanf(-x), 0.5);
}
}

// For small values, tanh(x) is x.
TEST(LlvmLibcAtanfTest, SpecialValues) {
for (uint32_t v : {0x3d8d6b23U, 0x3feefcfbU, 0xbd8d6b23U, 0xbfeefcfbU,
0x7F800000U, 0xFF800000U}) {
float x = float(FPBits(v));
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, x,
__llvm_libc::atanf(x), 0.5);
}
}
18 changes: 18 additions & 0 deletions libc/test/src/math/exhaustive/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,21 @@ add_fp_unittest(
LINK_LIBRARIES
-lpthread
)

add_fp_unittest(
atanf_test
NO_RUN_POSTBUILD
NEED_MPFR
SUITE
libc_math_exhaustive_tests
SRCS
atanf_test.cpp
DEPENDS
.exhaustive_test
libc.include.math
libc.src.math.atanf
libc.src.__support.FPUtil.fputil
LINK_LIBRARIES
-lpthread
)

76 changes: 76 additions & 0 deletions libc/test/src/math/exhaustive/atanf_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//===-- Exhaustive test for atanf -----------------------------------------===//
//
// 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/atanf.h"
#include "utils/MPFRWrapper/MPFRUtils.h"

#include <thread>

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

namespace mpfr = __llvm_libc::testing::mpfr;

struct LlvmLibcAtanfExhaustiveTest : 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::Atan, x,
__llvm_libc::atanf(x), 0.5, rounding);
} while (bits++ < stop);
return result;
}
};

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

// Range: [0, 1.0];
static const uint32_t POS_START = 0x0000'0000U;
static const uint32_t POS_STOP = FPBits::inf().uintval();

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

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

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

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

// Range: [-1.0, 0];
static const uint32_t NEG_START = 0x8000'0000U;
static const uint32_t NEG_STOP = FPBits::neg_inf().uintval();

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

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

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

TEST_F(LlvmLibcAtanfExhaustiveTest, NegativeRangeRoundTowardZero) {
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::TowardZero);
}
2 changes: 1 addition & 1 deletion libc/test/src/math/explogxf_test.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- Unittests for explogxf --------------------------------------------===//
//===-- Unittests for supfuncf --------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
32 changes: 32 additions & 0 deletions libc/test/src/math/inv_trigf_utils_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===-- Unittests for supfuncf --------------------------------------------===//
//
// 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 "in_float_range_test_helper.h"
#include "src/__support/FPUtil/FPBits.h"
#include "src/math/generic/inv_trigf_utils.h"
#include "utils/MPFRWrapper/MPFRUtils.h"
#include "utils/UnitTest/FPMatcher.h"
#include "utils/UnitTest/Test.h"
#include <math.h>

namespace mpfr = __llvm_libc::testing::mpfr;

DECLARE_SPECIAL_CONSTANTS(float)

constexpr int def_count = 100003;
constexpr float def_prec = 0.500001f;

TEST(LlvmLibcAtanfPosTest, InFloatRange) {
CHECK_DATA(0.0f, inf, mpfr::Operation::Atan, __llvm_libc::atan_eval, isfinite,
def_count, def_prec);
}

TEST(LlvmLibcAtanfNegTest, InFloatRange) {
CHECK_DATA(-0.0f, neg_inf, mpfr::Operation::Atan, __llvm_libc::atan_eval,
isfinite, def_count, def_prec);
}
8 changes: 8 additions & 0 deletions libc/utils/MPFRWrapper/MPFRUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ class MPFRNumber {
return result;
}

MPFRNumber atan() const {
MPFRNumber result(*this);
mpfr_atan(result.value, value, mpfr_rounding);
return result;
}

MPFRNumber atanh() const {
MPFRNumber result(*this);
mpfr_atanh(result.value, value, mpfr_rounding);
Expand Down Expand Up @@ -506,6 +512,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
switch (op) {
case Operation::Abs:
return mpfrInput.abs();
case Operation::Atan:
return mpfrInput.atan();
case Operation::Atanh:
return mpfrInput.atanh();
case Operation::Ceil:
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,
Atan,
Atanh,
Ceil,
Cos,
Expand Down