d09dc9324977e7c9ff91c4b8c7c40515eb939f72
[lldb.git] / libc / test / src / math / RIntTest.h
1 //===-- Utility class to test different flavors of rint ---------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H
10 #define LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H
11
12 #include "utils/FPUtil/FEnv.h"
13 #include "utils/FPUtil/FPBits.h"
14 #include "utils/FPUtil/TestHelpers.h"
15 #include "utils/MPFRWrapper/MPFRUtils.h"
16 #include "utils/UnitTest/Test.h"
17
18 #include <fenv.h>
19 #include <math.h>
20 #include <stdio.h>
21
22 namespace mpfr = __llvm_libc::testing::mpfr;
23
24 static constexpr int roundingModes[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,
25                                          FE_TONEAREST};
26
27 template <typename T>
28 class RIntTestTemplate : public __llvm_libc::testing::Test {
29 public:
30   typedef T (*RIntFunc)(T);
31
32 private:
33   using FPBits = __llvm_libc::fputil::FPBits<T>;
34   using UIntType = typename FPBits::UIntType;
35
36   const T zero = FPBits::zero();
37   const T negZero = FPBits::negZero();
38   const T inf = FPBits::inf();
39   const T negInf = FPBits::negInf();
40   const T nan = FPBits::buildNaN(1);
41
42   static inline mpfr::RoundingMode toMPFRRoundingMode(int mode) {
43     switch (mode) {
44     case FE_UPWARD:
45       return mpfr::RoundingMode::Upward;
46     case FE_DOWNWARD:
47       return mpfr::RoundingMode::Downward;
48     case FE_TOWARDZERO:
49       return mpfr::RoundingMode::TowardZero;
50     case FE_TONEAREST:
51       return mpfr::RoundingMode::Nearest;
52     default:
53       __builtin_unreachable();
54     }
55   }
56
57 public:
58   void testSpecialNumbers(RIntFunc func) {
59     for (int mode : roundingModes) {
60       __llvm_libc::fputil::setRound(mode);
61       ASSERT_FP_EQ(inf, func(inf));
62       ASSERT_FP_EQ(negInf, func(negInf));
63       ASSERT_FP_EQ(nan, func(nan));
64       ASSERT_FP_EQ(zero, func(zero));
65       ASSERT_FP_EQ(negZero, func(negZero));
66     }
67   }
68
69   void testRoundNumbers(RIntFunc func) {
70     for (int mode : roundingModes) {
71       __llvm_libc::fputil::setRound(mode);
72       mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
73       ASSERT_FP_EQ(func(T(1.0)), mpfr::Round(T(1.0), mpfrMode));
74       ASSERT_FP_EQ(func(T(-1.0)), mpfr::Round(T(-1.0), mpfrMode));
75       ASSERT_FP_EQ(func(T(10.0)), mpfr::Round(T(10.0), mpfrMode));
76       ASSERT_FP_EQ(func(T(-10.0)), mpfr::Round(T(-10.0), mpfrMode));
77       ASSERT_FP_EQ(func(T(1234.0)), mpfr::Round(T(1234.0), mpfrMode));
78       ASSERT_FP_EQ(func(T(-1234.0)), mpfr::Round(T(-1234.0), mpfrMode));
79     }
80   }
81
82   void testFractions(RIntFunc func) {
83     for (int mode : roundingModes) {
84       __llvm_libc::fputil::setRound(mode);
85       mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
86       ASSERT_FP_EQ(func(T(0.5)), mpfr::Round(T(0.5), mpfrMode));
87       ASSERT_FP_EQ(func(T(-0.5)), mpfr::Round(T(-0.5), mpfrMode));
88       ASSERT_FP_EQ(func(T(0.115)), mpfr::Round(T(0.115), mpfrMode));
89       ASSERT_FP_EQ(func(T(-0.115)), mpfr::Round(T(-0.115), mpfrMode));
90       ASSERT_FP_EQ(func(T(0.715)), mpfr::Round(T(0.715), mpfrMode));
91       ASSERT_FP_EQ(func(T(-0.715)), mpfr::Round(T(-0.715), mpfrMode));
92     }
93   }
94
95   void testSubnormalRange(RIntFunc func) {
96     constexpr UIntType count = 1000001;
97     constexpr UIntType step =
98         (FPBits::maxSubnormal - FPBits::minSubnormal) / count;
99     for (UIntType i = FPBits::minSubnormal; i <= FPBits::maxSubnormal;
100          i += step) {
101       T x = FPBits(i);
102       for (int mode : roundingModes) {
103         __llvm_libc::fputil::setRound(mode);
104         mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
105         ASSERT_FP_EQ(func(x), mpfr::Round(x, mpfrMode));
106       }
107     }
108   }
109
110   void testNormalRange(RIntFunc func) {
111     constexpr UIntType count = 1000001;
112     constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
113     for (UIntType i = FPBits::minNormal; i <= FPBits::maxNormal; i += step) {
114       T x = FPBits(i);
115       // In normal range on x86 platforms, the long double implicit 1 bit can be
116       // zero making the numbers NaN. We will skip them.
117       if (isnan(x)) {
118         continue;
119       }
120
121       for (int mode : roundingModes) {
122         __llvm_libc::fputil::setRound(mode);
123         mpfr::RoundingMode mpfrMode = toMPFRRoundingMode(mode);
124         ASSERT_FP_EQ(func(x), mpfr::Round(x, mpfrMode));
125       }
126     }
127   }
128 };
129
130 #define LIST_RINT_TESTS(F, func)                                               \
131   using RIntTest = RIntTestTemplate<F>;                                        \
132   TEST_F(RIntTest, specialNumbers) { testSpecialNumbers(&func); }              \
133   TEST_F(RIntTest, RoundNumbers) { testRoundNumbers(&func); }                  \
134   TEST_F(RIntTest, Fractions) { testFractions(&func); }                        \
135   TEST_F(RIntTest, SubnormalRange) { testSubnormalRange(&func); }              \
136   TEST_F(RIntTest, NormalRange) { testNormalRange(&func); }
137
138 #endif // LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H