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