[libc-commits] [libc] [libc][math] Add MPFR unit tests for nearbyint{, f, l, f16} (PR #94479)

via libc-commits libc-commits at lists.llvm.org
Wed Jun 5 07:51:58 PDT 2024


https://github.com/overmighty created https://github.com/llvm/llvm-project/pull/94479

None

>From 0a5c55cdae808a1da32b3203ea891baef6935c53 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Tue, 4 Jun 2024 20:35:46 +0200
Subject: [PATCH 1/9] [libc][math][c23] Checkout MPFRUtils.cpp from branch
 libc-math-ceilf16-mpfr-tests

---
 libc/utils/MPFRWrapper/MPFRUtils.cpp | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 18a8ac044a9bb..1e7467c8abbdf 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -12,6 +12,7 @@
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "src/__support/FPUtil/fpbits_str.h"
+#include "src/__support/macros/properties/types.h"
 #include "test/UnitTest/FPMatcher.h"
 
 #include "hdr/math_macros.h"
@@ -30,6 +31,10 @@ namespace mpfr {
 // precision compared to the floating point precision.
 template <typename T> struct ExtraPrecision;
 
+template <> struct ExtraPrecision<float16> {
+  static constexpr unsigned int VALUE = 128;
+};
+
 template <> struct ExtraPrecision<float> {
   static constexpr unsigned int VALUE = 128;
 };
@@ -85,9 +90,12 @@ class MPFRNumber {
 
   // We use explicit EnableIf specializations to disallow implicit
   // conversions. Implicit conversions can potentially lead to loss of
-  // precision.
-  template <typename XType,
-            cpp::enable_if_t<cpp::is_same_v<float, XType>, int> = 0>
+  // precision. We exceptionally allow implicit conversions from float16
+  // to float, as the MPFR API does not support float16, thus requiring
+  // conversion to a higher-precision format.
+  template <typename XType, cpp::enable_if_t<cpp::is_same_v<float, XType> ||
+                                                 cpp::is_same_v<float16, XType>,
+                                             int> = 0>
   explicit MPFRNumber(XType x,
                       unsigned int precision = ExtraPrecision<XType>::VALUE,
                       RoundingMode rounding = RoundingMode::Nearest)
@@ -529,8 +537,9 @@ class MPFRNumber {
     // If the control reaches here, it means that this number and input are
     // of the same sign but different exponent. In such a case, ULP error is
     // calculated as sum of two parts.
-    thisAsT = std::abs(thisAsT);
-    input = std::abs(input);
+    using U = cpp::conditional_t<cpp::is_same_v<T, float16>, float, T>;
+    thisAsT = std::abs(static_cast<U>(thisAsT));
+    input = std::abs(static_cast<U>(input));
     T min = thisAsT > input ? input : thisAsT;
     T max = thisAsT > input ? thisAsT : input;
     int minExponent = FPBits<T>(min).get_exponent();
@@ -585,6 +594,10 @@ template <> long double MPFRNumber::as<long double>() const {
   return mpfr_get_ld(value, mpfr_rounding);
 }
 
+template <> float16 MPFRNumber::as<float16>() const {
+  return static_cast<float16>(mpfr_get_flt(value, mpfr_rounding));
+}
+
 namespace internal {
 
 template <typename InputType>
@@ -763,6 +776,8 @@ template void explain_unary_operation_single_output_error<double>(
     Operation op, double, double, double, RoundingMode);
 template void explain_unary_operation_single_output_error<long double>(
     Operation op, long double, long double, double, RoundingMode);
+template void explain_unary_operation_single_output_error<float16>(
+    Operation op, float16, float16, double, RoundingMode);
 
 template <typename T>
 void explain_unary_operation_two_outputs_error(
@@ -942,6 +957,9 @@ template bool compare_unary_operation_single_output<double>(Operation, double,
                                                             RoundingMode);
 template bool compare_unary_operation_single_output<long double>(
     Operation, long double, long double, double, RoundingMode);
+template bool compare_unary_operation_single_output<float16>(Operation, float16,
+                                                             float16, double,
+                                                             RoundingMode);
 
 template <typename T>
 bool compare_unary_operation_two_outputs(Operation op, T input,

>From 4b2614ed3c91d94b1851d8106a70e7cb7bfd707a Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Tue, 4 Jun 2024 20:36:20 +0200
Subject: [PATCH 2/9] [libc][math][c23] Add rintf16 MPFR unit tests

---
 libc/test/src/math/CMakeLists.txt    | 19 +++++++++++++++++++
 libc/test/src/math/RIntTest.h        | 18 ++++++++++++------
 libc/test/src/math/rintf16_test.cpp  | 13 +++++++++++++
 libc/utils/MPFRWrapper/MPFRUtils.cpp |  1 +
 4 files changed, 45 insertions(+), 6 deletions(-)
 create mode 100644 libc/test/src/math/rintf16_test.cpp

diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 102188c332e40..e63d73b208c60 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -459,6 +459,7 @@ add_fp_unittest(
     RIntTest.h
   DEPENDS
     libc.src.math.rint
+    libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
@@ -474,6 +475,7 @@ add_fp_unittest(
     RIntTest.h
   DEPENDS
     libc.src.math.rintf
+    libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
@@ -489,6 +491,23 @@ add_fp_unittest(
     RIntTest.h
   DEPENDS
     libc.src.math.rintl
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  rintf16_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    rintf16_test.cpp
+  HDRS
+    RIntTest.h
+  DEPENDS
+    libc.src.math.rintf16
+    libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
diff --git a/libc/test/src/math/RIntTest.h b/libc/test/src/math/RIntTest.h
index 007b50427ba34..fb30327726133 100644
--- a/libc/test/src/math/RIntTest.h
+++ b/libc/test/src/math/RIntTest.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H
 #define LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H
 
+#include "src/__support/CPP/algorithm.h"
 #include "src/__support/FPUtil/FEnvImpl.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "test/UnitTest/FEnvSafeTest.h"
@@ -101,8 +102,10 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 
   void testSubnormalRange(RIntFunc func) {
-    constexpr StorageType COUNT = 100'001;
-    constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT;
+    constexpr int COUNT = 100'001;
+    constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max(
+        static_cast<StorageType>((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) {
@@ -114,13 +117,16 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   }
 
   void testNormalRange(RIntFunc func) {
-    constexpr StorageType COUNT = 100'001;
-    constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
+    constexpr int COUNT = 100'001;
+    constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max(
+        static_cast<StorageType>((MAX_NORMAL - MIN_NORMAL) / COUNT),
+        StorageType(1));
     for (StorageType i = MIN_NORMAL; i <= MAX_NORMAL; i += STEP) {
-      T x = FPBits(i).get_val();
+      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 (isnan(x)) {
+      if (xbits.is_nan()) {
         continue;
       }
 
diff --git a/libc/test/src/math/rintf16_test.cpp b/libc/test/src/math/rintf16_test.cpp
new file mode 100644
index 0000000000000..2adf2560bae1f
--- /dev/null
+++ b/libc/test/src/math/rintf16_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for rintf16 ---------------------------------------------===//
+//
+// 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 "RIntTest.h"
+
+#include "src/math/rintf16.h"
+
+LIST_RINT_TESTS(float16, LIBC_NAMESPACE::rintf16)
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 1e7467c8abbdf..28f61ffc015fe 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -1091,6 +1091,7 @@ template <typename T> T round(T x, RoundingMode mode) {
 template float round<float>(float, RoundingMode);
 template double round<double>(double, RoundingMode);
 template long double round<long double>(long double, RoundingMode);
+template float16 round<float16>(float16, RoundingMode);
 
 } // namespace mpfr
 } // namespace testing

>From 7aeea6b03e48be67a75b73b8cb47cbfc4ea9172f Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Tue, 4 Jun 2024 20:52:24 +0200
Subject: [PATCH 3/9] [libc][math][c23] Add {lrint,llrint,lround,llround}f16
 MPFR unit tests

---
 libc/test/src/math/CMakeLists.txt       | 110 ++++++++++++++++++++----
 libc/test/src/math/RoundToIntegerTest.h |  18 ++--
 libc/test/src/math/llrintf16_test.cpp   |  14 +++
 libc/test/src/math/llroundf16_test.cpp  |  13 +++
 libc/test/src/math/lrintf16_test.cpp    |  13 +++
 libc/test/src/math/lroundf16_test.cpp   |  13 +++
 6 files changed, 157 insertions(+), 24 deletions(-)
 create mode 100644 libc/test/src/math/llrintf16_test.cpp
 create mode 100644 libc/test/src/math/llroundf16_test.cpp
 create mode 100644 libc/test/src/math/lrintf16_test.cpp
 create mode 100644 libc/test/src/math/lroundf16_test.cpp

diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index e63d73b208c60..9c7e7d8083ad4 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -350,11 +350,11 @@ add_fp_unittest(
   HDRS
     RoundToIntegerTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.errno.errno
-    libc.src.fenv.feclearexcept
-    libc.src.fenv.feraiseexcept
-    libc.src.fenv.fetestexcept
     libc.src.math.lround
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
 
@@ -368,11 +368,11 @@ add_fp_unittest(
   HDRS
     RoundToIntegerTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.errno.errno
-    libc.src.fenv.feclearexcept
-    libc.src.fenv.feraiseexcept
-    libc.src.fenv.fetestexcept
     libc.src.math.lroundf
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
 
@@ -386,11 +386,29 @@ add_fp_unittest(
   HDRS
     RoundToIntegerTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.errno.errno
-    libc.src.fenv.feclearexcept
-    libc.src.fenv.feraiseexcept
-    libc.src.fenv.fetestexcept
     libc.src.math.lroundl
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  lroundf16_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    lroundf16_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.hdr.fenv_macros
+    libc.src.errno.errno
+    libc.src.math.lroundf16
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
 
@@ -404,11 +422,11 @@ add_fp_unittest(
   HDRS
     RoundToIntegerTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.errno.errno
-    libc.src.fenv.feclearexcept
-    libc.src.fenv.feraiseexcept
-    libc.src.fenv.fetestexcept
     libc.src.math.llround
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
 
@@ -422,11 +440,11 @@ add_fp_unittest(
   HDRS
     RoundToIntegerTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.errno.errno
-    libc.src.fenv.feclearexcept
-    libc.src.fenv.feraiseexcept
-    libc.src.fenv.fetestexcept
     libc.src.math.llroundf
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
 
@@ -440,11 +458,29 @@ add_fp_unittest(
   HDRS
     RoundToIntegerTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.errno.errno
-    libc.src.fenv.feclearexcept
-    libc.src.fenv.feraiseexcept
-    libc.src.fenv.fetestexcept
     libc.src.math.llroundl
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  llroundf16_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    llroundf16_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.hdr.fenv_macros
+    libc.src.errno.errno
+    libc.src.math.llroundf16
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
 
@@ -523,6 +559,7 @@ add_fp_unittest(
     RoundToIntegerTest.h
   DEPENDS
     libc.src.math.lrint
+    libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
@@ -538,6 +575,7 @@ add_fp_unittest(
     RoundToIntegerTest.h
   DEPENDS
     libc.src.math.lrintf
+    libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
@@ -553,6 +591,23 @@ add_fp_unittest(
     RoundToIntegerTest.h
   DEPENDS
     libc.src.math.lrintl
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  lrintf16_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    lrintf16_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.src.math.lrintf16
+    libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
@@ -568,6 +623,7 @@ add_fp_unittest(
     RoundToIntegerTest.h
   DEPENDS
     libc.src.math.llrint
+    libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
@@ -583,6 +639,7 @@ add_fp_unittest(
     RoundToIntegerTest.h
   DEPENDS
     libc.src.math.llrintf
+    libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
@@ -598,6 +655,23 @@ add_fp_unittest(
     RoundToIntegerTest.h
   DEPENDS
     libc.src.math.llrintl
+    libc.src.__support.CPP.algorithm
+    libc.src.__support.FPUtil.fenv_impl
+    libc.src.__support.FPUtil.fp_bits
+)
+
+add_fp_unittest(
+  llrintf16_test
+  NEED_MPFR
+  SUITE
+    libc-math-unittests
+  SRCS
+    llrintf16_test.cpp
+  HDRS
+    RoundToIntegerTest.h
+  DEPENDS
+    libc.src.math.llrintf16
+    libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
     libc.src.__support.FPUtil.fp_bits
 )
diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h
index d40e15080087c..67485c9595b24 100644
--- a/libc/test/src/math/RoundToIntegerTest.h
+++ b/libc/test/src/math/RoundToIntegerTest.h
@@ -9,6 +9,7 @@
 #ifndef LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
 #define LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
 
+#include "src/__support/CPP/algorithm.h"
 #include "src/__support/FPUtil/FEnvImpl.h"
 #include "src/__support/FPUtil/FPBits.h"
 #include "test/UnitTest/FEnvSafeTest.h"
@@ -226,8 +227,10 @@ class RoundToIntegerTestTemplate
   }
 
   void testSubnormalRange(RoundToIntegerFunc func) {
-    constexpr StorageType COUNT = 1'000'001;
-    constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT;
+    constexpr int COUNT = 1'000'001;
+    constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max(
+        static_cast<StorageType>((MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT),
+        StorageType(1));
     for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) {
       F x = FPBits(i).get_val();
       if (x == F(0.0))
@@ -268,13 +271,16 @@ class RoundToIntegerTestTemplate
     if (sizeof(I) > sizeof(long))
       return;
 
-    constexpr StorageType COUNT = 1'000'001;
-    constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT;
+    constexpr int COUNT = 1'000'001;
+    constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max(
+        static_cast<StorageType>((MAX_NORMAL - MIN_NORMAL) / COUNT),
+        StorageType(1));
     for (StorageType i = MIN_NORMAL; i <= MAX_NORMAL; i += STEP) {
-      F x = FPBits(i).get_val();
+      FPBits xbits(i);
+      F 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 (isnan(x)) {
+      if (xbits.is_nan()) {
         continue;
       }
 
diff --git a/libc/test/src/math/llrintf16_test.cpp b/libc/test/src/math/llrintf16_test.cpp
new file mode 100644
index 0000000000000..d16bd8f38b052
--- /dev/null
+++ b/libc/test/src/math/llrintf16_test.cpp
@@ -0,0 +1,14 @@
+//===-- Unittests for llrintf16 -------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "src/math/llrintf16.h"
+
+LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(float16, long long,
+                                       LIBC_NAMESPACE::llrintf16)
diff --git a/libc/test/src/math/llroundf16_test.cpp b/libc/test/src/math/llroundf16_test.cpp
new file mode 100644
index 0000000000000..9342b24fd5d04
--- /dev/null
+++ b/libc/test/src/math/llroundf16_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for llroundf16 ------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "src/math/llroundf16.h"
+
+LIST_ROUND_TO_INTEGER_TESTS(float16, long long, LIBC_NAMESPACE::llroundf16)
diff --git a/libc/test/src/math/lrintf16_test.cpp b/libc/test/src/math/lrintf16_test.cpp
new file mode 100644
index 0000000000000..28b1a1cb888d7
--- /dev/null
+++ b/libc/test/src/math/lrintf16_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for lrintf16 --------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "src/math/lrintf16.h"
+
+LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(float16, long, LIBC_NAMESPACE::lrintf16)
diff --git a/libc/test/src/math/lroundf16_test.cpp b/libc/test/src/math/lroundf16_test.cpp
new file mode 100644
index 0000000000000..3077134d58f91
--- /dev/null
+++ b/libc/test/src/math/lroundf16_test.cpp
@@ -0,0 +1,13 @@
+//===-- Unittests for lroundf16 -------------------------------------------===//
+//
+// 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 "RoundToIntegerTest.h"
+
+#include "src/math/lroundf16.h"
+
+LIST_ROUND_TO_INTEGER_TESTS(float16, long, LIBC_NAMESPACE::lroundf16)

>From 03511a57f42f73196152e16b4481acabe16cbb3c Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Wed, 5 Jun 2024 14:38:34 +0200
Subject: [PATCH 4/9] [libc][math][c23] Update RInt.h dependencies

---
 libc/test/src/math/CMakeLists.txt | 4 ++++
 libc/test/src/math/RIntTest.h     | 1 -
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt
index 9c7e7d8083ad4..10da42ccf6a20 100644
--- a/libc/test/src/math/CMakeLists.txt
+++ b/libc/test/src/math/CMakeLists.txt
@@ -494,6 +494,7 @@ add_fp_unittest(
   HDRS
     RIntTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.math.rint
     libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
@@ -510,6 +511,7 @@ add_fp_unittest(
   HDRS
     RIntTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.math.rintf
     libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
@@ -526,6 +528,7 @@ add_fp_unittest(
   HDRS
     RIntTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.math.rintl
     libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
@@ -542,6 +545,7 @@ add_fp_unittest(
   HDRS
     RIntTest.h
   DEPENDS
+    libc.hdr.fenv_macros
     libc.src.math.rintf16
     libc.src.__support.CPP.algorithm
     libc.src.__support.FPUtil.fenv_impl
diff --git a/libc/test/src/math/RIntTest.h b/libc/test/src/math/RIntTest.h
index fb30327726133..0f58d05e0cd63 100644
--- a/libc/test/src/math/RIntTest.h
+++ b/libc/test/src/math/RIntTest.h
@@ -19,7 +19,6 @@
 
 #include "hdr/fenv_macros.h"
 #include "hdr/math_macros.h"
-#include <stdio.h>
 
 namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
 

>From 69754e6ce34590be82482d0209b9d106c81edc5c Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Wed, 5 Jun 2024 14:43:06 +0200
Subject: [PATCH 5/9] [libc][math][c23] Remove braces from single-statement if
 body

---
 libc/test/src/math/RIntTest.h           | 3 +--
 libc/test/src/math/RoundToIntegerTest.h | 3 +--
 2 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/libc/test/src/math/RIntTest.h b/libc/test/src/math/RIntTest.h
index 0f58d05e0cd63..d31bf743f1a37 100644
--- a/libc/test/src/math/RIntTest.h
+++ b/libc/test/src/math/RIntTest.h
@@ -125,9 +125,8 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
       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()) {
+      if (xbits.is_nan())
         continue;
-      }
 
       for (int mode : ROUNDING_MODES) {
         LIBC_NAMESPACE::fputil::set_round(mode);
diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h
index 67485c9595b24..3de68e63e2d37 100644
--- a/libc/test/src/math/RoundToIntegerTest.h
+++ b/libc/test/src/math/RoundToIntegerTest.h
@@ -280,9 +280,8 @@ class RoundToIntegerTestTemplate
       F 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()) {
+      if (xbits.is_nan())
         continue;
-      }
 
       if (TestModes) {
         for (int m : ROUNDING_MODES) {

>From 8c29f63b2f87f9436f5ecec27fb4c187bb7f7bf7 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Wed, 5 Jun 2024 15:55:51 +0200
Subject: [PATCH 6/9] [libc][math][c23] Update MPFRUtils.cpp from branch
 libc-math-ceilf16-mpfr-tests

---
 libc/utils/MPFRWrapper/MPFRUtils.cpp | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 28f61ffc015fe..56fcb4b989ae0 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -31,9 +31,11 @@ namespace mpfr {
 // precision compared to the floating point precision.
 template <typename T> struct ExtraPrecision;
 
+#ifdef LIBC_TYPES_HAS_FLOAT16
 template <> struct ExtraPrecision<float16> {
   static constexpr unsigned int VALUE = 128;
 };
+#endif
 
 template <> struct ExtraPrecision<float> {
   static constexpr unsigned int VALUE = 128;
@@ -93,9 +95,13 @@ class MPFRNumber {
   // precision. We exceptionally allow implicit conversions from float16
   // to float, as the MPFR API does not support float16, thus requiring
   // conversion to a higher-precision format.
-  template <typename XType, cpp::enable_if_t<cpp::is_same_v<float, XType> ||
-                                                 cpp::is_same_v<float16, XType>,
-                                             int> = 0>
+  template <typename XType,
+            cpp::enable_if_t<cpp::is_same_v<float, XType>
+#ifdef LIBC_TYPES_HAS_FLOAT16
+                                 || cpp::is_same_v<float16, XType>
+#endif
+                             ,
+                             int> = 0>
   explicit MPFRNumber(XType x,
                       unsigned int precision = ExtraPrecision<XType>::VALUE,
                       RoundingMode rounding = RoundingMode::Nearest)
@@ -537,7 +543,12 @@ class MPFRNumber {
     // If the control reaches here, it means that this number and input are
     // of the same sign but different exponent. In such a case, ULP error is
     // calculated as sum of two parts.
+#ifdef LIBC_TYPES_HAS_FLOAT16
+    // TODO: This will no longer be needed once std::abs supports float16.
     using U = cpp::conditional_t<cpp::is_same_v<T, float16>, float, T>;
+#else
+    using U = T;
+#endif
     thisAsT = std::abs(static_cast<U>(thisAsT));
     input = std::abs(static_cast<U>(input));
     T min = thisAsT > input ? input : thisAsT;
@@ -594,9 +605,13 @@ template <> long double MPFRNumber::as<long double>() const {
   return mpfr_get_ld(value, mpfr_rounding);
 }
 
+#ifdef LIBC_TYPES_HAS_FLOAT16
 template <> float16 MPFRNumber::as<float16>() const {
-  return static_cast<float16>(mpfr_get_flt(value, mpfr_rounding));
+  // TODO: Either prove that this cast won't cause double-rounding errors, or
+  // find a better way to get a float16.
+  return static_cast<float16>(mpfr_get_d(value, mpfr_rounding));
 }
+#endif
 
 namespace internal {
 
@@ -776,8 +791,10 @@ template void explain_unary_operation_single_output_error<double>(
     Operation op, double, double, double, RoundingMode);
 template void explain_unary_operation_single_output_error<long double>(
     Operation op, long double, long double, double, RoundingMode);
+#ifdef LIBC_TYPES_HAS_FLOAT16
 template void explain_unary_operation_single_output_error<float16>(
     Operation op, float16, float16, double, RoundingMode);
+#endif
 
 template <typename T>
 void explain_unary_operation_two_outputs_error(
@@ -957,9 +974,11 @@ template bool compare_unary_operation_single_output<double>(Operation, double,
                                                             RoundingMode);
 template bool compare_unary_operation_single_output<long double>(
     Operation, long double, long double, double, RoundingMode);
+#ifdef LIBC_TYPES_HAS_FLOAT16
 template bool compare_unary_operation_single_output<float16>(Operation, float16,
                                                              float16, double,
                                                              RoundingMode);
+#endif
 
 template <typename T>
 bool compare_unary_operation_two_outputs(Operation op, T input,
@@ -1091,7 +1110,6 @@ template <typename T> T round(T x, RoundingMode mode) {
 template float round<float>(float, RoundingMode);
 template double round<double>(double, RoundingMode);
 template long double round<long double>(long double, RoundingMode);
-template float16 round<float16>(float16, RoundingMode);
 
 } // namespace mpfr
 } // namespace testing

>From 8492b25c09dd77b76f1508c1f5125af0335a0154 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Wed, 5 Jun 2024 16:15:04 +0200
Subject: [PATCH 7/9] [libc][math][c23] Fix RoundToIntegerTest.h

---
 libc/test/src/math/RoundToIntegerTest.h | 10 ++++++++--
 libc/utils/MPFRWrapper/MPFRUtils.cpp    |  9 +++++++++
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h
index 3de68e63e2d37..bb7e8643973c3 100644
--- a/libc/test/src/math/RoundToIntegerTest.h
+++ b/libc/test/src/math/RoundToIntegerTest.h
@@ -137,10 +137,13 @@ class RoundToIntegerTestTemplate
       return;
 
     constexpr int EXPONENT_LIMIT = sizeof(I) * 8 - 1;
+    constexpr int BIASED_EXPONENT_LIMIT = EXPONENT_LIMIT + FPBits::EXP_BIAS;
+    if (BIASED_EXPONENT_LIMIT > FPBits::MAX_BIASED_EXPONENT)
+      return;
     // We start with 1.0 so that the implicit bit for x86 long doubles
     // is set.
     FPBits bits(F(1.0));
-    bits.set_biased_exponent(EXPONENT_LIMIT + FPBits::EXP_BIAS);
+    bits.set_biased_exponent(BIASED_EXPONENT_LIMIT);
     bits.set_sign(Sign::NEG);
     bits.set_mantissa(0);
 
@@ -201,10 +204,13 @@ class RoundToIntegerTestTemplate
       return;
 
     constexpr int EXPONENT_LIMIT = sizeof(I) * 8 - 1;
+    constexpr int BIASED_EXPONENT_LIMIT = EXPONENT_LIMIT + FPBits::EXP_BIAS;
+    if (BIASED_EXPONENT_LIMIT > FPBits::MAX_BIASED_EXPONENT)
+      return;
     // We start with 1.0 so that the implicit bit for x86 long doubles
     // is set.
     FPBits bits(F(1.0));
-    bits.set_biased_exponent(EXPONENT_LIMIT + FPBits::EXP_BIAS);
+    bits.set_biased_exponent(BIASED_EXPONENT_LIMIT);
     bits.set_sign(Sign::NEG);
     bits.set_mantissa(FPBits::FRACTION_MASK);
 
diff --git a/libc/utils/MPFRWrapper/MPFRUtils.cpp b/libc/utils/MPFRWrapper/MPFRUtils.cpp
index 56fcb4b989ae0..a0cdf79e29355 100644
--- a/libc/utils/MPFRWrapper/MPFRUtils.cpp
+++ b/libc/utils/MPFRWrapper/MPFRUtils.cpp
@@ -1091,6 +1091,9 @@ template <typename T> bool round_to_long(T x, long &result) {
 template bool round_to_long<float>(float, long &);
 template bool round_to_long<double>(double, long &);
 template bool round_to_long<long double>(long double, long &);
+#ifdef LIBC_TYPES_HAS_FLOAT16
+template bool round_to_long<float16>(float16, long &);
+#endif
 
 template <typename T> bool round_to_long(T x, RoundingMode mode, long &result) {
   MPFRNumber mpfr(x);
@@ -1100,6 +1103,9 @@ template <typename T> bool round_to_long(T x, RoundingMode mode, long &result) {
 template bool round_to_long<float>(float, RoundingMode, long &);
 template bool round_to_long<double>(double, RoundingMode, long &);
 template bool round_to_long<long double>(long double, RoundingMode, long &);
+#ifdef LIBC_TYPES_HAS_FLOAT16
+template bool round_to_long<float16>(float16, RoundingMode, long &);
+#endif
 
 template <typename T> T round(T x, RoundingMode mode) {
   MPFRNumber mpfr(x);
@@ -1110,6 +1116,9 @@ template <typename T> T round(T x, RoundingMode mode) {
 template float round<float>(float, RoundingMode);
 template double round<double>(double, RoundingMode);
 template long double round<long double>(long double, RoundingMode);
+#ifdef LIBC_TYPES_HAS_FLOAT16
+template float16 round<float16>(float16, RoundingMode);
+#endif
 
 } // namespace mpfr
 } // namespace testing

>From d69f98733e6770a4be0940c3bd00c3dce76211c2 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Wed, 5 Jun 2024 16:39:55 +0200
Subject: [PATCH 8/9] [libc][math] Fix RIntTest.h not expecting FP exceptions

---
 libc/test/src/math/RIntTest.h | 45 ++++++++++++++++++++---------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/libc/test/src/math/RIntTest.h b/libc/test/src/math/RIntTest.h
index d31bf743f1a37..2c8b2e1138f00 100644
--- a/libc/test/src/math/RIntTest.h
+++ b/libc/test/src/math/RIntTest.h
@@ -66,11 +66,11 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
   void testSpecialNumbers(RIntFunc func) {
     for (int mode : ROUNDING_MODES) {
       LIBC_NAMESPACE::fputil::set_round(mode);
-      ASSERT_FP_EQ(inf, func(inf));
-      ASSERT_FP_EQ(neg_inf, func(neg_inf));
-      ASSERT_FP_EQ(nan, func(nan));
-      ASSERT_FP_EQ(zero, func(zero));
-      ASSERT_FP_EQ(neg_zero, func(neg_zero));
+      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));
     }
   }
 
@@ -78,12 +78,12 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
     for (int mode : ROUNDING_MODES) {
       LIBC_NAMESPACE::fputil::set_round(mode);
       mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode);
-      ASSERT_FP_EQ(func(T(1.0)), mpfr::round(T(1.0), mpfr_mode));
-      ASSERT_FP_EQ(func(T(-1.0)), mpfr::round(T(-1.0), mpfr_mode));
-      ASSERT_FP_EQ(func(T(10.0)), mpfr::round(T(10.0), mpfr_mode));
-      ASSERT_FP_EQ(func(T(-10.0)), mpfr::round(T(-10.0), mpfr_mode));
-      ASSERT_FP_EQ(func(T(1234.0)), mpfr::round(T(1234.0), mpfr_mode));
-      ASSERT_FP_EQ(func(T(-1234.0)), mpfr::round(T(-1234.0), mpfr_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));
     }
   }
 
@@ -91,12 +91,18 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
     for (int mode : ROUNDING_MODES) {
       LIBC_NAMESPACE::fputil::set_round(mode);
       mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode);
-      ASSERT_FP_EQ(func(T(0.5)), mpfr::round(T(0.5), mpfr_mode));
-      ASSERT_FP_EQ(func(T(-0.5)), mpfr::round(T(-0.5), mpfr_mode));
-      ASSERT_FP_EQ(func(T(0.115)), mpfr::round(T(0.115), mpfr_mode));
-      ASSERT_FP_EQ(func(T(-0.115)), mpfr::round(T(-0.115), mpfr_mode));
-      ASSERT_FP_EQ(func(T(0.715)), mpfr::round(T(0.715), mpfr_mode));
-      ASSERT_FP_EQ(func(T(-0.715)), mpfr::round(T(-0.715), mpfr_mode));
+      EXPECT_FP_EQ_WITH_EXCEPTION(func(T(0.5)), mpfr::round(T(0.5), mpfr_mode),
+                                  FE_INEXACT);
+      EXPECT_FP_EQ_WITH_EXCEPTION(func(T(-0.5)),
+                                  mpfr::round(T(-0.5), mpfr_mode), FE_INEXACT);
+      EXPECT_FP_EQ_WITH_EXCEPTION(func(T(0.115)),
+                                  mpfr::round(T(0.115), mpfr_mode), FE_INEXACT);
+      EXPECT_FP_EQ_WITH_EXCEPTION(
+          func(T(-0.115)), mpfr::round(T(-0.115), mpfr_mode), FE_INEXACT);
+      EXPECT_FP_EQ_WITH_EXCEPTION(func(T(0.715)),
+                                  mpfr::round(T(0.715), mpfr_mode), FE_INEXACT);
+      EXPECT_FP_EQ_WITH_EXCEPTION(
+          func(T(-0.715)), mpfr::round(T(-0.715), mpfr_mode), FE_INEXACT);
     }
   }
 
@@ -110,7 +116,8 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
       for (int mode : ROUNDING_MODES) {
         LIBC_NAMESPACE::fputil::set_round(mode);
         mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode);
-        ASSERT_FP_EQ(func(x), mpfr::round(x, mpfr_mode));
+        EXPECT_FP_EQ_WITH_EXCEPTION(func(x), mpfr::round(x, mpfr_mode),
+                                    FE_INEXACT);
       }
     }
   }
@@ -131,7 +138,7 @@ class RIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
       for (int mode : ROUNDING_MODES) {
         LIBC_NAMESPACE::fputil::set_round(mode);
         mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode);
-        ASSERT_FP_EQ(func(x), mpfr::round(x, mpfr_mode));
+        EXPECT_FP_EQ(func(x), mpfr::round(x, mpfr_mode));
       }
     }
   }

>From b22bafa1534d673740bccf807927f901d18efe79 Mon Sep 17 00:00:00 2001
From: OverMighty <its.overmighty at gmail.com>
Date: Wed, 5 Jun 2024 16:46:48 +0200
Subject: [PATCH 9/9] [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 10da42ccf6a20..7deecc911405d 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 0000000000000..4d21de0239e80
--- /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 <typename T>
+class NearbyIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
+public:
+  typedef T (*NearbyIntFunc)(T);
+
+private:
+  using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
+  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<StorageType>((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<StorageType>((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<F>;                      \
+  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 0000000000000..11a5c3372e73e
--- /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 0000000000000..e6ec250cec91f
--- /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 0000000000000..fd26153cfffb9
--- /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 0000000000000..a6d81a1439e17
--- /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)



More information about the libc-commits mailing list