[libc][NFC][obvious] fix the names of MPFR tests
[lldb.git] / libc / test / src / math / RoundToIntegerTest.h
1 //===-- Utility class to test different flavors of [l|ll]round --*- 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_ROUNDTOINTEGERTEST_H
10 #define LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
11
12 #include "src/errno/llvmlibc_errno.h"
13 #include "utils/FPUtil/FPBits.h"
14 #include "utils/MPFRWrapper/MPFRUtils.h"
15 #include "utils/UnitTest/Test.h"
16
17 #include <math.h>
18 #if math_errhandling & MATH_ERRNO
19 #include <errno.h>
20 #endif
21 #if math_errhandling & MATH_ERREXCEPT
22 #include "utils/FPUtil/FEnv.h"
23 #endif
24
25 namespace mpfr = __llvm_libc::testing::mpfr;
26
27 static constexpr int roundingModes[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,
28                                          FE_TONEAREST};
29
30 template <typename F, typename I, bool TestModes = false>
31 class RoundToIntegerTestTemplate : public __llvm_libc::testing::Test {
32 public:
33   typedef I (*RoundToIntegerFunc)(F);
34
35 private:
36   using FPBits = __llvm_libc::fputil::FPBits<F>;
37   using UIntType = typename FPBits::UIntType;
38
39   const F zero = __llvm_libc::fputil::FPBits<F>::zero();
40   const F negZero = __llvm_libc::fputil::FPBits<F>::negZero();
41   const F inf = __llvm_libc::fputil::FPBits<F>::inf();
42   const F negInf = __llvm_libc::fputil::FPBits<F>::negInf();
43   const F nan = __llvm_libc::fputil::FPBits<F>::buildNaN(1);
44   static constexpr I IntegerMin = I(1) << (sizeof(I) * 8 - 1);
45   static constexpr I IntegerMax = -(IntegerMin + 1);
46
47   void testOneInput(RoundToIntegerFunc func, F input, I expected,
48                     bool expectError) {
49 #if math_errhandling & MATH_ERRNO
50     llvmlibc_errno = 0;
51 #endif
52 #if math_errhandling & MATH_ERREXCEPT
53     __llvm_libc::fputil::clearExcept(FE_ALL_EXCEPT);
54 #endif
55
56     ASSERT_EQ(func(input), expected);
57
58     if (expectError) {
59 #if math_errhandling & MATH_ERREXCEPT
60       ASSERT_EQ(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT), FE_INVALID);
61 #endif
62 #if math_errhandling & MATH_ERRNO
63       ASSERT_EQ(llvmlibc_errno, EDOM);
64 #endif
65     } else {
66 #if math_errhandling & MATH_ERREXCEPT
67       ASSERT_EQ(__llvm_libc::fputil::testExcept(FE_ALL_EXCEPT), 0);
68 #endif
69 #if math_errhandling & MATH_ERRNO
70       ASSERT_EQ(llvmlibc_errno, 0);
71 #endif
72     }
73   }
74
75   static inline mpfr::RoundingMode toMPFRRoundingMode(int mode) {
76     switch (mode) {
77     case FE_UPWARD:
78       return mpfr::RoundingMode::Upward;
79     case FE_DOWNWARD:
80       return mpfr::RoundingMode::Downward;
81     case FE_TOWARDZERO:
82       return mpfr::RoundingMode::TowardZero;
83     case FE_TONEAREST:
84       return mpfr::RoundingMode::Nearest;
85     default:
86       __builtin_unreachable();
87     }
88   }
89
90 public:
91   void SetUp() override {
92 #if math_errhandling & MATH_ERREXCEPT
93     // We will disable all exceptions so that the test will not
94     // crash with SIGFPE. We can still use fetestexcept to check
95     // if the appropriate flag was raised.
96     __llvm_libc::fputil::disableExcept(FE_ALL_EXCEPT);
97 #endif
98   }
99
100   void doInfinityAndNaNTest(RoundToIntegerFunc func) {
101     testOneInput(func, inf, IntegerMax, true);
102     testOneInput(func, negInf, IntegerMin, true);
103     testOneInput(func, nan, IntegerMax, true);
104   }
105
106   void testInfinityAndNaN(RoundToIntegerFunc func) {
107     if (TestModes) {
108       for (int mode : roundingModes) {
109         __llvm_libc::fputil::setRound(mode);
110         doInfinityAndNaNTest(func);
111       }
112     } else {
113       doInfinityAndNaNTest(func);
114     }
115   }
116
117   void doRoundNumbersTest(RoundToIntegerFunc func) {
118     testOneInput(func, zero, I(0), false);
119     testOneInput(func, negZero, I(0), false);
120     testOneInput(func, F(1.0), I(1), false);
121     testOneInput(func, F(-1.0), I(-1), false);
122     testOneInput(func, F(10.0), I(10), false);
123     testOneInput(func, F(-10.0), I(-10), false);
124     testOneInput(func, F(1234.0), I(1234), false);
125     testOneInput(func, F(-1234.0), I(-1234), false);
126
127     // The rest of this this function compares with an equivalent MPFR function
128     // which rounds floating point numbers to long values. There is no MPFR
129     // function to round to long long or wider integer values. So, we will
130     // the remaining tests only if the width of I less than equal to that of
131     // long.
132     if (sizeof(I) > sizeof(long))
133       return;
134
135     constexpr int exponentLimit = sizeof(I) * 8 - 1;
136     // We start with 1.0 so that the implicit bit for x86 long doubles
137     // is set.
138     FPBits bits(F(1.0));
139     bits.exponent = exponentLimit + FPBits::exponentBias;
140     bits.sign = 1;
141     bits.mantissa = 0;
142
143     F x = bits;
144     long mpfrResult;
145     bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
146     ASSERT_FALSE(erangeflag);
147     testOneInput(func, x, mpfrResult, false);
148   }
149
150   void testRoundNumbers(RoundToIntegerFunc func) {
151     if (TestModes) {
152       for (int mode : roundingModes) {
153         __llvm_libc::fputil::setRound(mode);
154         doRoundNumbersTest(func);
155       }
156     } else {
157       doRoundNumbersTest(func);
158     }
159   }
160
161   void doFractionsTest(RoundToIntegerFunc func, int mode) {
162     constexpr F fractions[] = {0.5, -0.5, 0.115, -0.115, 0.715, -0.715};
163     for (F x : fractions) {
164       long mpfrLongResult;
165       bool erangeflag;
166       if (TestModes)
167         erangeflag =
168             mpfr::RoundToLong(x, toMPFRRoundingMode(mode), mpfrLongResult);
169       else
170         erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
171       ASSERT_FALSE(erangeflag);
172       I mpfrResult = mpfrLongResult;
173       testOneInput(func, x, mpfrResult, false);
174     }
175   }
176
177   void testFractions(RoundToIntegerFunc func) {
178     if (TestModes) {
179       for (int mode : roundingModes) {
180         __llvm_libc::fputil::setRound(mode);
181         doFractionsTest(func, mode);
182       }
183     } else {
184       // Passing 0 for mode has no effect as it is not used in doFractionsTest
185       // when `TestModes` is false;
186       doFractionsTest(func, 0);
187     }
188   }
189
190   void testIntegerOverflow(RoundToIntegerFunc func) {
191     // This function compares with an equivalent MPFR function which rounds
192     // floating point numbers to long values. There is no MPFR function to
193     // round to long long or wider integer values. So, we will peform the
194     // comparisons in this function only if the width of I less than equal to
195     // that of long.
196     if (sizeof(I) > sizeof(long))
197       return;
198
199     constexpr int exponentLimit = sizeof(I) * 8 - 1;
200     // We start with 1.0 so that the implicit bit for x86 long doubles
201     // is set.
202     FPBits bits(F(1.0));
203     bits.exponent = exponentLimit + FPBits::exponentBias;
204     bits.sign = 1;
205     bits.mantissa = UIntType(0x1)
206                     << (__llvm_libc::fputil::MantissaWidth<F>::value - 1);
207
208     F x = bits;
209     if (TestModes) {
210       for (int m : roundingModes) {
211         __llvm_libc::fputil::setRound(m);
212         long mpfrLongResult;
213         bool erangeflag =
214             mpfr::RoundToLong(x, toMPFRRoundingMode(m), mpfrLongResult);
215         ASSERT_TRUE(erangeflag);
216         testOneInput(func, x, IntegerMin, true);
217       }
218     } else {
219       long mpfrLongResult;
220       bool erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
221       ASSERT_TRUE(erangeflag);
222       testOneInput(func, x, IntegerMin, true);
223     }
224   }
225
226   void testSubnormalRange(RoundToIntegerFunc func) {
227     constexpr UIntType count = 1000001;
228     constexpr UIntType step =
229         (FPBits::maxSubnormal - FPBits::minSubnormal) / count;
230     for (UIntType i = FPBits::minSubnormal; i <= FPBits::maxSubnormal;
231          i += step) {
232       F x = FPBits(i);
233       if (x == F(0.0))
234         continue;
235       // All subnormal numbers should round to zero.
236       if (TestModes) {
237         if (x > 0) {
238           __llvm_libc::fputil::setRound(FE_UPWARD);
239           testOneInput(func, x, I(1), false);
240           __llvm_libc::fputil::setRound(FE_DOWNWARD);
241           testOneInput(func, x, I(0), false);
242           __llvm_libc::fputil::setRound(FE_TOWARDZERO);
243           testOneInput(func, x, I(0), false);
244           __llvm_libc::fputil::setRound(FE_TONEAREST);
245           testOneInput(func, x, I(0), false);
246         } else {
247           __llvm_libc::fputil::setRound(FE_UPWARD);
248           testOneInput(func, x, I(0), false);
249           __llvm_libc::fputil::setRound(FE_DOWNWARD);
250           testOneInput(func, x, I(-1), false);
251           __llvm_libc::fputil::setRound(FE_TOWARDZERO);
252           testOneInput(func, x, I(0), false);
253           __llvm_libc::fputil::setRound(FE_TONEAREST);
254           testOneInput(func, x, I(0), false);
255         }
256       } else {
257         testOneInput(func, x, 0L, false);
258       }
259     }
260   }
261
262   void testNormalRange(RoundToIntegerFunc func) {
263     // This function compares with an equivalent MPFR function which rounds
264     // floating point numbers to long values. There is no MPFR function to
265     // round to long long or wider integer values. So, we will peform the
266     // comparisons in this function only if the width of I less than equal to
267     // that of long.
268     if (sizeof(I) > sizeof(long))
269       return;
270
271     constexpr UIntType count = 1000001;
272     constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
273     for (UIntType i = FPBits::minNormal; i <= FPBits::maxNormal; i += step) {
274       F x = FPBits(i);
275       // In normal range on x86 platforms, the long double implicit 1 bit can be
276       // zero making the numbers NaN. We will skip them.
277       if (isnan(x)) {
278         continue;
279       }
280
281       if (TestModes) {
282         for (int m : roundingModes) {
283           long mpfrLongResult;
284           bool erangeflag =
285               mpfr::RoundToLong(x, toMPFRRoundingMode(m), mpfrLongResult);
286           I mpfrResult = mpfrLongResult;
287           __llvm_libc::fputil::setRound(m);
288           if (erangeflag)
289             testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
290           else
291             testOneInput(func, x, mpfrResult, false);
292         }
293       } else {
294         long mpfrLongResult;
295         bool erangeflag = mpfr::RoundToLong(x, mpfrLongResult);
296         I mpfrResult = mpfrLongResult;
297         if (erangeflag)
298           testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
299         else
300           testOneInput(func, x, mpfrResult, false);
301       }
302     }
303   }
304 };
305
306 #define LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, TestModes)              \
307   using LlvmLibcRoundToIntegerTest =                                           \
308       RoundToIntegerTestTemplate<F, I, TestModes>;                             \
309   TEST_F(LlvmLibcRoundToIntegerTest, InfinityAndNaN) {                         \
310     testInfinityAndNaN(&func);                                                 \
311   }                                                                            \
312   TEST_F(LlvmLibcRoundToIntegerTest, RoundNumbers) {                           \
313     testRoundNumbers(&func);                                                   \
314   }                                                                            \
315   TEST_F(LlvmLibcRoundToIntegerTest, Fractions) { testFractions(&func); }      \
316   TEST_F(LlvmLibcRoundToIntegerTest, IntegerOverflow) {                        \
317     testIntegerOverflow(&func);                                                \
318   }                                                                            \
319   TEST_F(LlvmLibcRoundToIntegerTest, SubnormalRange) {                         \
320     testSubnormalRange(&func);                                                 \
321   }                                                                            \
322   TEST_F(LlvmLibcRoundToIntegerTest, NormalRange) { testNormalRange(&func); }
323
324 #define LIST_ROUND_TO_INTEGER_TESTS(F, I, func)                                \
325   LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, false)
326
327 #define LIST_ROUND_TO_INTEGER_TESTS_WITH_MODES(F, I, func)                     \
328   LIST_ROUND_TO_INTEGER_TESTS_HELPER(F, I, func, true)
329
330 #endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H