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 "src/fenv/feclearexcept.h"
14 #include "src/fenv/feraiseexcept.h"
15 #include "src/fenv/fetestexcept.h"
16 #include "utils/FPUtil/FPBits.h"
17 #include "utils/MPFRWrapper/MPFRUtils.h"
18 #include "utils/UnitTest/Test.h"
19 
20 #include <math.h>
21 #if math_errhandling & MATH_ERRNO
22 #include <errno.h>
23 #endif
24 #if math_errhandling & MATH_ERREXCEPT
25 #include "utils/FPUtil/FEnv.h"
26 #endif
27 
28 namespace mpfr = __llvm_libc::testing::mpfr;
29 
30 template <typename F, typename I>
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::feclearexcept(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::fetestexcept(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::fetestexcept(FE_ALL_EXCEPT), 0);
68 #endif
69 #if math_errhandling & MATH_ERRNO
70       ASSERT_EQ(llvmlibc_errno, 0);
71 #endif
72     }
73   }
74 
75 public:
76   void SetUp() override {
77 #if math_errhandling & MATH_ERREXCEPT
78     // We will disable all exceptions so that the test will not
79     // crash with SIGFPE. We can still use fetestexcept to check
80     // if the appropriate flag was raised.
81     __llvm_libc::fputil::disableExcept(FE_ALL_EXCEPT);
82 #endif
83   }
84 
85   void testInfinityAndNaN(RoundToIntegerFunc func) {
86     testOneInput(func, inf, IntegerMax, true);
87     testOneInput(func, negInf, IntegerMin, true);
88     testOneInput(func, nan, IntegerMax, true);
89   }
90 
91   void testRoundNumbers(RoundToIntegerFunc func) {
92     testOneInput(func, zero, I(0), false);
93     testOneInput(func, negZero, I(0), false);
94     testOneInput(func, F(1.0), I(1), false);
95     testOneInput(func, F(-1.0), I(-1), false);
96     testOneInput(func, F(10.0), I(10), false);
97     testOneInput(func, F(-10.0), I(-10), false);
98     testOneInput(func, F(1234.0), I(1234), false);
99     testOneInput(func, F(-1234.0), I(-1234), false);
100 
101     // The rest of this this function compares with an equivalent MPFR function
102     // which rounds floating point numbers to long values. There is no MPFR
103     // function to round to long long or wider integer values. So, we will
104     // the remaining tests only if the width of I less than equal to that of
105     // long.
106     if (sizeof(I) > sizeof(long))
107       return;
108 
109     constexpr int exponentLimit = sizeof(I) * 8 - 1;
110     // We start with 1.0 so that the implicit bit for x86 long doubles
111     // is set.
112     FPBits bits(F(1.0));
113     bits.exponent = exponentLimit + FPBits::exponentBias;
114     bits.sign = 1;
115     bits.mantissa = 0;
116 
117     F x = bits;
118     long mpfrResult;
119     bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
120     ASSERT_FALSE(erangeflag);
121     testOneInput(func, x, mpfrResult, false);
122   }
123 
124   void testFractions(RoundToIntegerFunc func) {
125     testOneInput(func, F(0.5), I(1), false);
126     testOneInput(func, F(-0.5), I(-1), false);
127     testOneInput(func, F(0.115), I(0), false);
128     testOneInput(func, F(-0.115), I(0), false);
129     testOneInput(func, F(0.715), I(1), false);
130     testOneInput(func, F(-0.715), I(-1), false);
131   }
132 
133   void testIntegerOverflow(RoundToIntegerFunc func) {
134     // This function compares with an equivalent MPFR function which rounds
135     // floating point numbers to long values. There is no MPFR function to
136     // round to long long or wider integer values. So, we will peform the
137     // comparisons in this function only if the width of I less than equal to
138     // that of long.
139     if (sizeof(I) > sizeof(long))
140       return;
141 
142     constexpr int exponentLimit = sizeof(I) * 8 - 1;
143     // We start with 1.0 so that the implicit bit for x86 long doubles
144     // is set.
145     FPBits bits(F(1.0));
146     bits.exponent = exponentLimit + FPBits::exponentBias;
147     bits.sign = 1;
148     bits.mantissa = UIntType(0x1)
149                     << (__llvm_libc::fputil::MantissaWidth<F>::value - 1);
150 
151     F x = bits;
152     long mpfrResult;
153     bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
154     ASSERT_TRUE(erangeflag);
155     testOneInput(func, x, IntegerMin, true);
156   }
157 
158   void testSubnormalRange(RoundToIntegerFunc func) {
159     // This function compares with an equivalent MPFR function which rounds
160     // floating point numbers to long values. There is no MPFR function to
161     // round to long long or wider integer values. So, we will peform the
162     // comparisons in this function only if the width of I less than equal to
163     // that of long.
164     if (sizeof(I) > sizeof(long))
165       return;
166 
167     constexpr UIntType count = 1000001;
168     constexpr UIntType step =
169         (FPBits::maxSubnormal - FPBits::minSubnormal) / count;
170     for (UIntType i = FPBits::minSubnormal; i <= FPBits::maxSubnormal;
171          i += step) {
172       F x = FPBits(i);
173       // All subnormal numbers should round to zero.
174       testOneInput(func, x, 0L, false);
175     }
176   }
177 
178   void testNormalRange(RoundToIntegerFunc func) {
179     // This function compares with an equivalent MPFR function which rounds
180     // floating point numbers to long values. There is no MPFR function to
181     // round to long long or wider integer values. So, we will peform the
182     // comparisons in this function only if the width of I less than equal to
183     // that of long.
184     if (sizeof(I) > sizeof(long))
185       return;
186 
187     constexpr UIntType count = 1000001;
188     constexpr UIntType step = (FPBits::maxNormal - FPBits::minNormal) / count;
189     for (UIntType i = FPBits::minNormal; i <= FPBits::maxNormal; i += step) {
190       F x = FPBits(i);
191       // In normal range on x86 platforms, the long double implicit 1 bit can be
192       // zero making the numbers NaN. We will skip them.
193       if (isnan(x)) {
194         continue;
195       }
196 
197       long mpfrResult;
198       bool erangeflag = mpfr::RoundToLong(x, mpfrResult);
199       if (erangeflag)
200         testOneInput(func, x, x > 0 ? IntegerMax : IntegerMin, true);
201       else
202         testOneInput(func, x, mpfrResult, false);
203     }
204   }
205 };
206 
207 #define LIST_ROUND_TO_INTEGER_TESTS(F, I, func)                                \
208   using RoundToIntegerTest = RoundToIntegerTestTemplate<F, I>;                 \
209   TEST_F(RoundToIntegerTest, InfinityAndNaN) { testInfinityAndNaN(&func); }    \
210   TEST_F(RoundToIntegerTest, RoundNumbers) { testRoundNumbers(&func); }        \
211   TEST_F(RoundToIntegerTest, Fractions) { testFractions(&func); }              \
212   TEST_F(RoundToIntegerTest, IntegerOverflow) { testIntegerOverflow(&func); }  \
213   TEST_F(RoundToIntegerTest, SubnormalRange) { testSubnormalRange(&func); }    \
214   TEST_F(RoundToIntegerTest, NormalRange) { testNormalRange(&func); }
215 
216 #endif // LLVM_LIBC_TEST_SRC_MATH_ROUNDTOINTEGERTEST_H
217