From 44a2589cfc7fa2d3486f60000166a7dea0621494 Mon Sep 17 00:00:00 2001 From: OverMighty Date: Mon, 1 Jul 2024 14:45:36 +0200 Subject: [PATCH] [libc][math] Add MPFR unit tests for nearbyint{,f,l,f16} (#94479) --- libc/test/src/math/CMakeLists.txt | 60 ++++++++++++ libc/test/src/math/NearbyIntTest.h | 118 +++++++++++++++++++++++ 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, 230 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 1326d0830d7d9d..729d9feeaae8aa 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -586,6 +586,66 @@ 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.src.math.nearbyint + libc.src.__support.CPP.algorithm + libc.src.__support.CPP.array +) + +add_fp_unittest( + nearbyintf_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyintf_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.src.math.nearbyintf + libc.src.__support.CPP.algorithm + libc.src.__support.CPP.array +) + +add_fp_unittest( + nearbyintl_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyintl_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.src.math.nearbyintl + libc.src.__support.CPP.algorithm + libc.src.__support.CPP.array +) + +add_fp_unittest( + nearbyintf16_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + nearbyintf16_test.cpp + HDRS + NearbyIntTest.h + DEPENDS + libc.src.math.nearbyintf16 + libc.src.__support.CPP.algorithm + libc.src.__support.CPP.array +) + 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..88cdf453f05567 --- /dev/null +++ b/libc/test/src/math/NearbyIntTest.h @@ -0,0 +1,118 @@ +//===-- 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/CPP/array.h" +#include "test/UnitTest/FEnvSafeTest.h" +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +using namespace LIBC_NAMESPACE::fputil::testing; + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +template +class NearbyIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { + + DECLARE_SPECIAL_CONSTANTS(T) + + static constexpr LIBC_NAMESPACE::cpp::array ROUNDING_MODES = + { + RoundingMode::Upward, + RoundingMode::Downward, + RoundingMode::TowardZero, + RoundingMode::Nearest, + }; + + 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(); + +public: + using NearbyIntFunc = T (*)(T); + + void test_round_numbers(NearbyIntFunc func) { + for (RoundingMode mode : ROUNDING_MODES) { + if (ForceRoundingMode r(mode); r.success) { + EXPECT_FP_EQ(func(T(1.0)), mpfr::round(T(1.0), mode)); + EXPECT_FP_EQ(func(T(-1.0)), mpfr::round(T(-1.0), mode)); + EXPECT_FP_EQ(func(T(10.0)), mpfr::round(T(10.0), mode)); + EXPECT_FP_EQ(func(T(-10.0)), mpfr::round(T(-10.0), mode)); + EXPECT_FP_EQ(func(T(1234.0)), mpfr::round(T(1234.0), mode)); + EXPECT_FP_EQ(func(T(-1234.0)), mpfr::round(T(-1234.0), mode)); + } + } + } + + void test_fractions(NearbyIntFunc func) { + for (RoundingMode mode : ROUNDING_MODES) { + if (ForceRoundingMode r(mode); r.success) { + EXPECT_FP_EQ(func(T(0.5)), mpfr::round(T(0.5), mode)); + EXPECT_FP_EQ(func(T(-0.5)), mpfr::round(T(-0.5), mode)); + EXPECT_FP_EQ(func(T(0.115)), mpfr::round(T(0.115), mode)); + EXPECT_FP_EQ(func(T(-0.115)), mpfr::round(T(-0.115), mode)); + EXPECT_FP_EQ(func(T(0.715)), mpfr::round(T(0.715), mode)); + EXPECT_FP_EQ(func(T(-0.715)), mpfr::round(T(-0.715), mode)); + } + } + } + + void test_subnormal_range(NearbyIntFunc func) { + constexpr int COUNT = 100'001; + const 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 (RoundingMode mode : ROUNDING_MODES) { + if (ForceRoundingMode r(mode); r.success) { + EXPECT_FP_EQ(func(x), mpfr::round(x, mode)); + } + } + } + } + + void test_normal_range(NearbyIntFunc func) { + constexpr int COUNT = 100'001; + const 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 (RoundingMode mode : ROUNDING_MODES) { + if (ForceRoundingMode r(mode); r.success) { + EXPECT_FP_EQ(func(x), mpfr::round(x, mode)); + } + } + } + } +}; + +#define LIST_NEARBYINT_TESTS(F, func) \ + using LlvmLibcNearbyIntTest = NearbyIntTestTemplate; \ + TEST_F(LlvmLibcNearbyIntTest, RoundNumbers) { test_round_numbers(&func); } \ + TEST_F(LlvmLibcNearbyIntTest, Fractions) { test_fractions(&func); } \ + TEST_F(LlvmLibcNearbyIntTest, SubnormalRange) { \ + test_subnormal_range(&func); \ + } \ + TEST_F(LlvmLibcNearbyIntTest, NormalRange) { test_normal_range(&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)