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