From b22bafa1534d673740bccf807927f901d18efe79 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Wed, 5 Jun 2024 16:46:48 +0200 Subject: [PATCH] [libc][math] Add MPFR unit tests for nearbyint{,f,l,f16} --- libc/test/src/math/CMakeLists.txt | 68 +++++++++++ libc/test/src/math/NearbyIntTest.h | 148 +++++++++++++++++++++++ libc/test/src/math/nearbyint_test.cpp | 13 ++ libc/test/src/math/nearbyintf16_test.cpp | 13 ++ libc/test/src/math/nearbyintf_test.cpp | 13 ++ libc/test/src/math/nearbyintl_test.cpp | 13 ++ 6 files changed, 268 insertions(+) create mode 100644 libc/test/src/math/NearbyIntTest.h create mode 100644 libc/test/src/math/nearbyint_test.cpp create mode 100644 libc/test/src/math/nearbyintf16_test.cpp create mode 100644 libc/test/src/math/nearbyintf_test.cpp create mode 100644 libc/test/src/math/nearbyintl_test.cpp diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index 10da42ccf6a20a..7deecc911405d0 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -484,6 +484,74 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + nearbyint_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyint_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.math.nearbyint + libc.src.__support.CPP.algorithm + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + nearbyintf_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyintf_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.math.nearbyintf + libc.src.__support.CPP.algorithm + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + nearbyintl_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyintl_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.math.nearbyintl + libc.src.__support.CPP.algorithm + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + nearbyintf16_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyintf16_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.hdr.fenv_macros + libc.src.math.nearbyintf16 + libc.src.__support.CPP.algorithm + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits +) + add_fp_unittest( rint_test NEED_MPFR diff --git a/libc/test/src/math/NearbyIntTest.h b/libc/test/src/math/NearbyIntTest.h new file mode 100644 index 00000000000000..4d21de0239e80e --- /dev/null +++ b/libc/test/src/math/NearbyIntTest.h @@ -0,0 +1,148 @@ +//===-- Utility class to test different flavors of nearbyint ----*- 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_TEST_SRC_MATH_NEARBYINTTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_NEARBYINTTEST_H + +#include "src/__support/CPP/algorithm.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +#include "hdr/fenv_macros.h" +#include "hdr/math_macros.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +static constexpr int ROUNDING_MODES[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO, + FE_TONEAREST}; + +template +class NearbyIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { +public: + typedef T (*NearbyIntFunc)(T); + +private: + using FPBits = LIBC_NAMESPACE::fputil::FPBits; + using StorageType = typename FPBits::StorageType; + + const T inf = FPBits::inf(Sign::POS).get_val(); + const T neg_inf = FPBits::inf(Sign::NEG).get_val(); + const T zero = FPBits::zero(Sign::POS).get_val(); + const T neg_zero = FPBits::zero(Sign::NEG).get_val(); + const T nan = FPBits::quiet_nan().get_val(); + + static constexpr StorageType MIN_SUBNORMAL = + FPBits::min_subnormal().uintval(); + static constexpr StorageType MAX_SUBNORMAL = + FPBits::max_subnormal().uintval(); + static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval(); + static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval(); + + static inline mpfr::RoundingMode to_mpfr_rounding_mode(int mode) { + switch (mode) { + case FE_UPWARD: + return mpfr::RoundingMode::Upward; + case FE_DOWNWARD: + return mpfr::RoundingMode::Downward; + case FE_TOWARDZERO: + return mpfr::RoundingMode::TowardZero; + case FE_TONEAREST: + return mpfr::RoundingMode::Nearest; + default: + __builtin_unreachable(); + } + } + +public: + void testSpecialNumbers(NearbyIntFunc func) { + for (int mode : ROUNDING_MODES) { + LIBC_NAMESPACE::fputil::set_round(mode); + EXPECT_FP_EQ(inf, func(inf)); + EXPECT_FP_EQ(neg_inf, func(neg_inf)); + EXPECT_FP_EQ(nan, func(nan)); + EXPECT_FP_EQ(zero, func(zero)); + EXPECT_FP_EQ(neg_zero, func(neg_zero)); + } + } + + void testRoundNumbers(NearbyIntFunc func) { + for (int mode : ROUNDING_MODES) { + LIBC_NAMESPACE::fputil::set_round(mode); + mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); + EXPECT_FP_EQ(func(T(1.0)), mpfr::round(T(1.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(-1.0)), mpfr::round(T(-1.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(10.0)), mpfr::round(T(10.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(-10.0)), mpfr::round(T(-10.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(1234.0)), mpfr::round(T(1234.0), mpfr_mode)); + EXPECT_FP_EQ(func(T(-1234.0)), mpfr::round(T(-1234.0), mpfr_mode)); + } + } + + void testFractions(NearbyIntFunc func) { + for (int mode : ROUNDING_MODES) { + LIBC_NAMESPACE::fputil::set_round(mode); + mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); + EXPECT_FP_EQ(func(T(0.5)), mpfr::round(T(0.5), mpfr_mode)); + EXPECT_FP_EQ(func(T(-0.5)), mpfr::round(T(-0.5), mpfr_mode)); + EXPECT_FP_EQ(func(T(0.115)), mpfr::round(T(0.115), mpfr_mode)); + EXPECT_FP_EQ(func(T(-0.115)), mpfr::round(T(-0.115), mpfr_mode)); + EXPECT_FP_EQ(func(T(0.715)), mpfr::round(T(0.715), mpfr_mode)); + EXPECT_FP_EQ(func(T(-0.715)), mpfr::round(T(-0.715), mpfr_mode)); + } + } + + void testSubnormalRange(NearbyIntFunc func) { + constexpr int COUNT = 100'001; + constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max( + static_cast((MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT), + StorageType(1)); + for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) { + T x = FPBits(i).get_val(); + for (int mode : ROUNDING_MODES) { + LIBC_NAMESPACE::fputil::set_round(mode); + mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); + EXPECT_FP_EQ(func(x), mpfr::round(x, mpfr_mode)); + } + } + } + + void testNormalRange(NearbyIntFunc func) { + constexpr int COUNT = 100'001; + constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max( + static_cast((MAX_NORMAL - MIN_NORMAL) / COUNT), + StorageType(1)); + for (StorageType i = MIN_NORMAL; i <= MAX_NORMAL; i += STEP) { + FPBits xbits(i); + T x = xbits.get_val(); + // In normal range on x86 platforms, the long double implicit 1 bit can be + // zero making the numbers NaN. We will skip them. + if (xbits.is_nan()) + continue; + + for (int mode : ROUNDING_MODES) { + LIBC_NAMESPACE::fputil::set_round(mode); + mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode); + EXPECT_FP_EQ(func(x), mpfr::round(x, mpfr_mode)); + } + } + } +}; + +#define LIST_NEARBYINT_TESTS(F, func) \ + using LlvmLibcNearbyIntTest = NearbyIntTestTemplate; \ + TEST_F(LlvmLibcNearbyIntTest, specialNumbers) { testSpecialNumbers(&func); } \ + TEST_F(LlvmLibcNearbyIntTest, RoundNumbers) { testRoundNumbers(&func); } \ + TEST_F(LlvmLibcNearbyIntTest, Fractions) { testFractions(&func); } \ + TEST_F(LlvmLibcNearbyIntTest, SubnormalRange) { testSubnormalRange(&func); } \ + TEST_F(LlvmLibcNearbyIntTest, NormalRange) { testNormalRange(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_NEARBYINTTEST_H diff --git a/libc/test/src/math/nearbyint_test.cpp b/libc/test/src/math/nearbyint_test.cpp new file mode 100644 index 00000000000000..11a5c3372e73ea --- /dev/null +++ b/libc/test/src/math/nearbyint_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for nearbyint -------------------------------------------===// +// +// 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 "NearbyIntTest.h" + +#include "src/math/nearbyint.h" + +LIST_NEARBYINT_TESTS(double, LIBC_NAMESPACE::nearbyint) diff --git a/libc/test/src/math/nearbyintf16_test.cpp b/libc/test/src/math/nearbyintf16_test.cpp new file mode 100644 index 00000000000000..e6ec250cec91fe --- /dev/null +++ b/libc/test/src/math/nearbyintf16_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for nearbyintf16 ----------------------------------------===// +// +// 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 "NearbyIntTest.h" + +#include "src/math/nearbyintf16.h" + +LIST_NEARBYINT_TESTS(float16, LIBC_NAMESPACE::nearbyintf16) diff --git a/libc/test/src/math/nearbyintf_test.cpp b/libc/test/src/math/nearbyintf_test.cpp new file mode 100644 index 00000000000000..fd26153cfffb94 --- /dev/null +++ b/libc/test/src/math/nearbyintf_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for nearbyintf ------------------------------------------===// +// +// 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 "NearbyIntTest.h" + +#include "src/math/nearbyintf.h" + +LIST_NEARBYINT_TESTS(float, LIBC_NAMESPACE::nearbyintf) diff --git a/libc/test/src/math/nearbyintl_test.cpp b/libc/test/src/math/nearbyintl_test.cpp new file mode 100644 index 00000000000000..a6d81a1439e17c --- /dev/null +++ b/libc/test/src/math/nearbyintl_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for nearbyintl ------------------------------------------===// +// +// 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 "NearbyIntTest.h" + +#include "src/math/nearbyintl.h" + +LIST_NEARBYINT_TESTS(long double, LIBC_NAMESPACE::nearbyintl)