diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 2742c33ae478..b522e7f03015 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -494,6 +494,9 @@ set(TARGET_LIBM_ENTRYPOINTS libc.src.math.round libc.src.math.roundf libc.src.math.roundl + libc.src.math.roundeven + libc.src.math.roundevenf + libc.src.math.roundevenl libc.src.math.scalbn libc.src.math.scalbnf libc.src.math.scalbnl @@ -555,6 +558,7 @@ if(LIBC_TYPES_HAS_FLOAT128) libc.src.math.nextdownf128 libc.src.math.nextupf128 libc.src.math.rintf128 + libc.src.math.roundevenf128 libc.src.math.roundf128 libc.src.math.sqrtf128 libc.src.math.truncf128 diff --git a/libc/docs/c23.rst b/libc/docs/c23.rst index 3f64722bc8e6..152178eaf751 100644 --- a/libc/docs/c23.rst +++ b/libc/docs/c23.rst @@ -54,7 +54,7 @@ Additions: * pown* * powr* * rootn* - * roundeven* + * roundeven* |check| * fromfp* * ufromfp* * fromfpx* diff --git a/libc/docs/math/index.rst b/libc/docs/math/index.rst index 970a43ca87c9..7a7b6c9c8db5 100644 --- a/libc/docs/math/index.rst +++ b/libc/docs/math/index.rst @@ -206,7 +206,7 @@ Basic Operations +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | round | |check| | |check| | |check| | | |check| | 7.12.9.6 | F.10.6.6 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ -| roundeven | | | | | | 7.12.9.8 | F.10.6.8 | +| roundeven | |check| | |check| | |check| | | |check| | 7.12.9.8 | F.10.6.8 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ | scalbn | |check| | |check| | |check| | | | 7.12.6.19 | F.10.3.19 | +------------------+------------------+-----------------+------------------------+----------------------+------------------------+------------------------+----------------------------+ diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt index c89792b8ac7b..e8f699fabe36 100644 --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -293,6 +293,11 @@ add_math_entrypoint_object(roundf) add_math_entrypoint_object(roundl) add_math_entrypoint_object(roundf128) +add_math_entrypoint_object(roundeven) +add_math_entrypoint_object(roundevenf) +add_math_entrypoint_object(roundevenl) +add_math_entrypoint_object(roundevenf128) + add_math_entrypoint_object(scalbn) add_math_entrypoint_object(scalbnf) add_math_entrypoint_object(scalbnl) diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index dc77f8b5ddba..5bc9066c6263 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -417,6 +417,55 @@ add_entrypoint_object( libc.src.__support.FPUtil.nearest_integer_operations ) +add_entrypoint_object( + roundeven + SRCS + roundeven.cpp + HDRS + ../roundeven.h + COMPILE_OPTIONS + -O3 + DEPENDS + libc.src.__support.FPUtil.nearest_integer_operations +) + +add_entrypoint_object( + roundevenf + SRCS + roundevenf.cpp + HDRS + ../roundevenf.h + COMPILE_OPTIONS + -O3 + DEPENDS + libc.src.__support.FPUtil.nearest_integer_operations +) + +add_entrypoint_object( + roundevenl + SRCS + roundevenl.cpp + HDRS + ../roundevenl.h + COMPILE_OPTIONS + -O3 + DEPENDS + libc.src.__support.FPUtil.nearest_integer_operations +) + +add_entrypoint_object( + roundevenf128 + SRCS + roundevenf128.cpp + HDRS + ../roundevenf128.h + COMPILE_OPTIONS + -O3 + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.nearest_integer_operations +) + add_entrypoint_object( lround SRCS diff --git a/libc/src/math/generic/roundeven.cpp b/libc/src/math/generic/roundeven.cpp new file mode 100644 index 000000000000..5f2adf9b5fce --- /dev/null +++ b/libc/src/math/generic/roundeven.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of roundeven 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/roundeven.h" +#include "src/__support/FPUtil/NearestIntegerOperations.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(double, roundeven, (double x)) { + return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/roundevenf.cpp b/libc/src/math/generic/roundevenf.cpp new file mode 100644 index 000000000000..353bec74ecf0 --- /dev/null +++ b/libc/src/math/generic/roundevenf.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of roundevenf 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/roundevenf.h" +#include "src/__support/FPUtil/NearestIntegerOperations.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float, roundevenf, (float x)) { + return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/roundevenf128.cpp b/libc/src/math/generic/roundevenf128.cpp new file mode 100644 index 000000000000..259388c86fd3 --- /dev/null +++ b/libc/src/math/generic/roundevenf128.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of roundevenf128 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/roundevenf128.h" +#include "src/__support/FPUtil/NearestIntegerOperations.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(float128, roundevenf128, (float128 x)) { + return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/generic/roundevenl.cpp b/libc/src/math/generic/roundevenl.cpp new file mode 100644 index 000000000000..f8f429faeec8 --- /dev/null +++ b/libc/src/math/generic/roundevenl.cpp @@ -0,0 +1,19 @@ +//===-- Implementation of roundevenl 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/roundevenl.h" +#include "src/__support/FPUtil/NearestIntegerOperations.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { + +LLVM_LIBC_FUNCTION(long double, roundevenl, (long double x)) { + return fputil::round_using_specific_rounding_mode(x, FP_INT_TONEAREST); +} + +} // namespace LIBC_NAMESPACE diff --git a/libc/src/math/roundeven.h b/libc/src/math/roundeven.h new file mode 100644 index 000000000000..9c76b1fe334a --- /dev/null +++ b/libc/src/math/roundeven.h @@ -0,0 +1,18 @@ +//===-- Implementation header for roundeven ---------------------*- 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_ROUNDEVEN_H +#define LLVM_LIBC_SRC_MATH_ROUNDEVEN_H + +namespace LIBC_NAMESPACE { + +double roundeven(double x); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_ROUNDEVEN_H diff --git a/libc/src/math/roundevenf.h b/libc/src/math/roundevenf.h new file mode 100644 index 000000000000..447e7fd940c1 --- /dev/null +++ b/libc/src/math/roundevenf.h @@ -0,0 +1,18 @@ +//===-- Implementation header for roundevenf --------------------*- 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_ROUNDEVENF_H +#define LLVM_LIBC_SRC_MATH_ROUNDEVENF_H + +namespace LIBC_NAMESPACE { + +float roundevenf(float x); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENF_H diff --git a/libc/src/math/roundevenf128.h b/libc/src/math/roundevenf128.h new file mode 100644 index 000000000000..589839d09075 --- /dev/null +++ b/libc/src/math/roundevenf128.h @@ -0,0 +1,20 @@ +//===-- Implementation header for roundevenf128 -----------------*- 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_ROUNDEVENF128_H +#define LLVM_LIBC_SRC_MATH_ROUNDEVENF128_H + +#include "src/__support/macros/properties/types.h" + +namespace LIBC_NAMESPACE { + +float128 roundevenf128(float128 x); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENF128_H diff --git a/libc/src/math/roundevenl.h b/libc/src/math/roundevenl.h new file mode 100644 index 000000000000..a2f3397e4479 --- /dev/null +++ b/libc/src/math/roundevenl.h @@ -0,0 +1,18 @@ +//===-- Implementation header for roundevenl --------------------*- 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_ROUNDEVENL_H +#define LLVM_LIBC_SRC_MATH_ROUNDEVENL_H + +namespace LIBC_NAMESPACE { + +long double roundevenl(long double x); + +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC_MATH_ROUNDEVENL_H diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt index bbf8f071e1e0..d928cb5c6475 100644 --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -323,6 +323,51 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + roundeven_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + roundeven_test.cpp + HDRS + RoundEvenTest.h + DEPENDS + libc.include.math + libc.src.math.roundeven + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + roundevenf_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + roundevenf_test.cpp + HDRS + RoundEvenTest.h + DEPENDS + libc.include.math + libc.src.math.roundevenf + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + roundevenl_test + NEED_MPFR + SUITE + libc-math-unittests + SRCS + roundevenl_test.cpp + HDRS + RoundEvenTest.h + DEPENDS + libc.include.math + libc.src.math.roundevenl + libc.src.__support.FPUtil.fp_bits +) + add_fp_unittest( lround_test NEED_MPFR diff --git a/libc/test/src/math/RoundEvenTest.h b/libc/test/src/math/RoundEvenTest.h new file mode 100644 index 000000000000..db7263a39c0f --- /dev/null +++ b/libc/test/src/math/RoundEvenTest.h @@ -0,0 +1,92 @@ +//===-- Utility class to test roundeven[f|l] --------------------*- 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_ROUNDEVENTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_ROUNDEVENTEST_H + +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" +#include "utils/MPFRWrapper/MPFRUtils.h" + +#include "include/llvm-libc-macros/math-macros.h" + +namespace mpfr = LIBC_NAMESPACE::testing::mpfr; + +template +class RoundEvenTest : public LIBC_NAMESPACE::testing::Test { + + DECLARE_SPECIAL_CONSTANTS(T) + +public: + typedef T (*RoundEvenFunc)(T); + + void testSpecialNumbers(RoundEvenFunc func) { + EXPECT_FP_EQ(zero, func(zero)); + EXPECT_FP_EQ(neg_zero, func(neg_zero)); + + EXPECT_FP_EQ(inf, func(inf)); + EXPECT_FP_EQ(neg_inf, func(neg_inf)); + + EXPECT_FP_EQ(aNaN, func(aNaN)); + } + + void testRoundedNumbers(RoundEvenFunc func) { + EXPECT_FP_EQ(T(1.0), func(T(1.0))); + EXPECT_FP_EQ(T(-1.0), func(T(-1.0))); + EXPECT_FP_EQ(T(10.0), func(T(10.0))); + EXPECT_FP_EQ(T(-10.0), func(T(-10.0))); + EXPECT_FP_EQ(T(1234.0), func(T(1234.0))); + EXPECT_FP_EQ(T(-1234.0), func(T(-1234.0))); + } + + void testFractions(RoundEvenFunc func) { + EXPECT_FP_EQ(T(0.0), func(T(0.5))); + EXPECT_FP_EQ(T(-0.0), func(T(-0.5))); + EXPECT_FP_EQ(T(0.0), func(T(0.115))); + EXPECT_FP_EQ(T(-0.0), func(T(-0.115))); + EXPECT_FP_EQ(T(1.0), func(T(0.715))); + EXPECT_FP_EQ(T(-1.0), func(T(-0.715))); + EXPECT_FP_EQ(T(1.0), func(T(1.3))); + EXPECT_FP_EQ(T(-1.0), func(T(-1.3))); + EXPECT_FP_EQ(T(2.0), func(T(1.5))); + EXPECT_FP_EQ(T(-2.0), func(T(-1.5))); + EXPECT_FP_EQ(T(2.0), func(T(1.75))); + EXPECT_FP_EQ(T(-2.0), func(T(-1.75))); + EXPECT_FP_EQ(T(11.0), func(T(10.65))); + EXPECT_FP_EQ(T(-11.0), func(T(-10.65))); + EXPECT_FP_EQ(T(1233.0), func(T(1233.25))); + EXPECT_FP_EQ(T(1234.0), func(T(1233.50))); + EXPECT_FP_EQ(T(1234.0), func(T(1233.75))); + EXPECT_FP_EQ(T(-1233.0), func(T(-1233.25))); + EXPECT_FP_EQ(T(-1234.0), func(T(-1233.50))); + EXPECT_FP_EQ(T(-1234.0), func(T(-1233.75))); + EXPECT_FP_EQ(T(1234.0), func(T(1234.50))); + EXPECT_FP_EQ(T(-1234.0), func(T(-1234.50))); + } + + void testRange(RoundEvenFunc func) { + constexpr StorageType COUNT = 100'000; + constexpr StorageType STEP = STORAGE_MAX / COUNT; + for (StorageType i = 0, v = 0; i <= COUNT; ++i, v += STEP) { + T x = FPBits(v).get_val(); + if (isnan(x) || isinf(x)) + continue; + + ASSERT_MPFR_MATCH(mpfr::Operation::RoundEven, x, func(x), 0.0); + } + } +}; + +#define LIST_ROUNDEVEN_TESTS(T, func) \ + using LlvmLibcRoundEvenTest = RoundEvenTest; \ + TEST_F(LlvmLibcRoundEvenTest, SpecialNumbers) { testSpecialNumbers(&func); } \ + TEST_F(LlvmLibcRoundEvenTest, RoundedNubmers) { testRoundedNumbers(&func); } \ + TEST_F(LlvmLibcRoundEvenTest, Fractions) { testFractions(&func); } \ + TEST_F(LlvmLibcRoundEvenTest, Range) { testRange(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDEVENTEST_H diff --git a/libc/test/src/math/roundeven_test.cpp b/libc/test/src/math/roundeven_test.cpp new file mode 100644 index 000000000000..cd1a7bf2429f --- /dev/null +++ b/libc/test/src/math/roundeven_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for roundeven -------------------------------------------===// +// +// 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 "RoundEvenTest.h" + +#include "src/math/roundeven.h" + +LIST_ROUNDEVEN_TESTS(double, LIBC_NAMESPACE::roundeven) diff --git a/libc/test/src/math/roundevenf_test.cpp b/libc/test/src/math/roundevenf_test.cpp new file mode 100644 index 000000000000..68dff9b3eca9 --- /dev/null +++ b/libc/test/src/math/roundevenf_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for roundevenf ------------------------------------------===// +// +// 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 "RoundEvenTest.h" + +#include "src/math/roundevenf.h" + +LIST_ROUNDEVEN_TESTS(float, LIBC_NAMESPACE::roundevenf) diff --git a/libc/test/src/math/roundevenl_test.cpp b/libc/test/src/math/roundevenl_test.cpp new file mode 100644 index 000000000000..f4031bd65ec2 --- /dev/null +++ b/libc/test/src/math/roundevenl_test.cpp @@ -0,0 +1,13 @@ +//===-- Unittests for roundevenl ------------------------------------------===// +// +// 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 "RoundEvenTest.h" + +#include "src/math/roundevenl.h" + +LIST_ROUNDEVEN_TESTS(long double, LIBC_NAMESPACE::roundevenl) diff --git a/libc/test/src/math/smoke/CMakeLists.txt b/libc/test/src/math/smoke/CMakeLists.txt index 4ac1842cf5fa..e9ff35577b95 100644 --- a/libc/test/src/math/smoke/CMakeLists.txt +++ b/libc/test/src/math/smoke/CMakeLists.txt @@ -397,6 +397,62 @@ add_fp_unittest( libc.src.__support.FPUtil.fp_bits ) +add_fp_unittest( + roundeven_test + SUITE + libc-math-smoke-tests + SRCS + roundeven_test.cpp + HDRS + RoundEvenTest.h + DEPENDS + libc.include.math + libc.src.math.roundeven + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + roundevenf_test + SUITE + libc-math-smoke-tests + SRCS + roundevenf_test.cpp + HDRS + RoundEvenTest.h + DEPENDS + libc.include.math + libc.src.math.roundevenf + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + roundevenl_test + SUITE + libc-math-smoke-tests + SRCS + roundevenl_test.cpp + HDRS + RoundEvenTest.h + DEPENDS + libc.include.math + libc.src.math.roundevenl + libc.src.__support.FPUtil.fp_bits +) + +add_fp_unittest( + roundevenf128_test + SUITE + libc-math-smoke-tests + SRCS + roundevenf128_test.cpp + HDRS + RoundEvenTest.h + DEPENDS + libc.include.math + libc.src.math.roundevenf128 + libc.src.__support.FPUtil.fp_bits +) + add_fp_unittest( lround_test SUITE diff --git a/libc/test/src/math/smoke/RoundEvenTest.h b/libc/test/src/math/smoke/RoundEvenTest.h new file mode 100644 index 000000000000..107052fa0e28 --- /dev/null +++ b/libc/test/src/math/smoke/RoundEvenTest.h @@ -0,0 +1,72 @@ +//===-- Utility class to test roundeven[f|l] --------------------*- 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_SMOKE_ROUNDEVENTEST_H +#define LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDEVENTEST_H + +#include "test/UnitTest/FPMatcher.h" +#include "test/UnitTest/Test.h" + +#include "include/llvm-libc-macros/math-macros.h" + +template +class RoundEvenTest : public LIBC_NAMESPACE::testing::Test { + + DECLARE_SPECIAL_CONSTANTS(T) + +public: + typedef T (*RoundEvenFunc)(T); + + void testSpecialNumbers(RoundEvenFunc func) { + EXPECT_FP_EQ(zero, func(zero)); + EXPECT_FP_EQ(neg_zero, func(neg_zero)); + + EXPECT_FP_EQ(inf, func(inf)); + EXPECT_FP_EQ(neg_inf, func(neg_inf)); + + EXPECT_FP_EQ(aNaN, func(aNaN)); + } + + void testRoundedNumbers(RoundEvenFunc func) { + EXPECT_FP_EQ(T(1.0), func(T(1.0))); + EXPECT_FP_EQ(T(-1.0), func(T(-1.0))); + EXPECT_FP_EQ(T(10.0), func(T(10.0))); + EXPECT_FP_EQ(T(-10.0), func(T(-10.0))); + EXPECT_FP_EQ(T(1234.0), func(T(1234.0))); + EXPECT_FP_EQ(T(-1234.0), func(T(-1234.0))); + } + + void testFractions(RoundEvenFunc func) { + EXPECT_FP_EQ(T(0.0), func(T(0.5))); + EXPECT_FP_EQ(T(-0.0), func(T(-0.5))); + EXPECT_FP_EQ(T(0.0), func(T(0.115))); + EXPECT_FP_EQ(T(-0.0), func(T(-0.115))); + EXPECT_FP_EQ(T(1.0), func(T(0.715))); + EXPECT_FP_EQ(T(-1.0), func(T(-0.715))); + EXPECT_FP_EQ(T(2.0), func(T(1.5))); + EXPECT_FP_EQ(T(-2.0), func(T(-1.5))); + EXPECT_FP_EQ(T(2.0), func(T(1.75))); + EXPECT_FP_EQ(T(-2.0), func(T(-1.75))); + EXPECT_FP_EQ(T(10.0), func(T(10.50))); + EXPECT_FP_EQ(T(-10.0), func(T(-10.50))); + EXPECT_FP_EQ(T(11.0), func(T(10.65))); + EXPECT_FP_EQ(T(-11.0), func(T(-10.65))); + EXPECT_FP_EQ(T(1234.0), func(T(1234.50))); + EXPECT_FP_EQ(T(-1234.0), func(T(-1234.50))); + EXPECT_FP_EQ(T(1236.0), func(T(1235.50))); + EXPECT_FP_EQ(T(-1236.0), func(T(-1235.50))); + } +}; + +#define LIST_ROUNDEVEN_TESTS(T, func) \ + using LlvmLibcRoundEvenTest = RoundEvenTest; \ + TEST_F(LlvmLibcRoundEvenTest, SpecialNumbers) { testSpecialNumbers(&func); } \ + TEST_F(LlvmLibcRoundEvenTest, RoundedNubmers) { testRoundedNumbers(&func); } \ + TEST_F(LlvmLibcRoundEvenTest, Fractions) { testFractions(&func); } + +#endif // LLVM_LIBC_TEST_SRC_MATH_SMOKE_ROUNDEVENTEST_H diff --git a/libc/test/src/math/smoke/roundeven_test.cpp b/libc/test/src/math/smoke/roundeven_test.cpp new file mode 100644 index 000000000000..e2d625fb0d31 --- /dev/null +++ b/libc/test/src/math/smoke/roundeven_test.cpp @@ -0,0 +1,12 @@ +//===-- Unittests for roundeven -------------------------------------------===// +// +// 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 "RoundEvenTest.h" +#include "src/math/roundeven.h" + +LIST_ROUNDEVEN_TESTS(double, LIBC_NAMESPACE::roundeven) diff --git a/libc/test/src/math/smoke/roundevenf128_test.cpp b/libc/test/src/math/smoke/roundevenf128_test.cpp new file mode 100644 index 000000000000..a1fdc40d577e --- /dev/null +++ b/libc/test/src/math/smoke/roundevenf128_test.cpp @@ -0,0 +1,12 @@ +//===-- Unittests for roundevenf128 ---------------------------------------===// +// +// 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 "RoundEvenTest.h" +#include "src/math/roundevenf128.h" + +LIST_ROUNDEVEN_TESTS(float128, LIBC_NAMESPACE::roundevenf128) diff --git a/libc/test/src/math/smoke/roundevenf_test.cpp b/libc/test/src/math/smoke/roundevenf_test.cpp new file mode 100644 index 000000000000..f033e26988fa --- /dev/null +++ b/libc/test/src/math/smoke/roundevenf_test.cpp @@ -0,0 +1,12 @@ +//===-- Unittests for roundevenf ------------------------------------------===// +// +// 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 "RoundEvenTest.h" +#include "src/math/roundevenf.h" + +LIST_ROUNDEVEN_TESTS(float, LIBC_NAMESPACE::roundevenf) diff --git a/libc/test/src/math/smoke/roundevenl_test.cpp b/libc/test/src/math/smoke/roundevenl_test.cpp new file mode 100644 index 000000000000..be09f1283aa7 --- /dev/null +++ b/libc/test/src/math/smoke/roundevenl_test.cpp @@ -0,0 +1,12 @@ +//===-- Unittests for roundevenf ------------------------------------------===// +// +// 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 "RoundEvenTest.h" +#include "src/math/roundevenl.h" + +LIST_ROUNDEVEN_TESTS(long double, LIBC_NAMESPACE::roundevenl) diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp index eaa47da6bda2..938e2c3c0edf 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.cpp +++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp @@ -351,6 +351,16 @@ public: return result; } + MPFRNumber roundeven() const { + MPFRNumber result(*this); +#if MPFR_VERSION_MAJOR >= 4 + mpfr_roundeven(result.value, value); +#else + mpfr_rint(result.value, value, MPFR_RNDN); +#endif + return result; + } + bool round_to_long(long &result) const { // We first calculate the rounded value. This way, when converting // to long using mpfr_get_si, the rounding direction of MPFR_RNDN @@ -634,6 +644,8 @@ unary_operation(Operation op, InputType input, unsigned int precision, return mpfrInput.mod_pi_over_4(); case Operation::Round: return mpfrInput.round(); + case Operation::RoundEven: + return mpfrInput.roundeven(); case Operation::Sin: return mpfrInput.sin(); case Operation::Sinh: diff --git a/libc/utils/MPFRWrapper/MPFRUtils.h b/libc/utils/MPFRWrapper/MPFRUtils.h index 0a41ac639798..d2f73e2628e1 100644 --- a/libc/utils/MPFRWrapper/MPFRUtils.h +++ b/libc/utils/MPFRWrapper/MPFRUtils.h @@ -49,6 +49,7 @@ enum class Operation : int { ModPIOver2, ModPIOver4, Round, + RoundEven, Sin, Sinh, Sqrt,