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