1 //===-- Utility class to test different flavors of remquo -------*- 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_REMQUOTEST_H 10 #define LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H 11 12 #include "hdr/math_macros.h" 13 #include "src/__support/FPUtil/BasicOperations.h" 14 #include "src/__support/FPUtil/FPBits.h" 15 #include "test/UnitTest/FEnvSafeTest.h" 16 #include "test/UnitTest/FPMatcher.h" 17 #include "test/UnitTest/Test.h" 18 #include "utils/MPFRWrapper/MPFRUtils.h" 19 20 namespace mpfr = LIBC_NAMESPACE::testing::mpfr; 21 22 template <typename T> 23 class RemQuoTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest { 24 using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>; 25 using StorageType = typename FPBits::StorageType; 26 27 const T inf = FPBits::inf(Sign::POS).get_val(); 28 const T neg_inf = FPBits::inf(Sign::NEG).get_val(); 29 const T zero = FPBits::zero(Sign::POS).get_val(); 30 const T neg_zero = FPBits::zero(Sign::NEG).get_val(); 31 const T nan = FPBits::quiet_nan().get_val(); 32 33 static constexpr StorageType MIN_SUBNORMAL = 34 FPBits::min_subnormal().uintval(); 35 static constexpr StorageType MAX_SUBNORMAL = 36 FPBits::max_subnormal().uintval(); 37 static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval(); 38 static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval(); 39 40 public: 41 typedef T (*RemQuoFunc)(T, T, int *); 42 testSpecialNumbers(RemQuoFunc func)43 void testSpecialNumbers(RemQuoFunc func) { 44 int quotient; 45 T x, y; 46 47 y = T(1.0); 48 x = inf; 49 EXPECT_FP_EQ(nan, func(x, y, "ient)); 50 x = neg_inf; 51 EXPECT_FP_EQ(nan, func(x, y, "ient)); 52 53 x = T(1.0); 54 y = zero; 55 EXPECT_FP_EQ(nan, func(x, y, "ient)); 56 y = neg_zero; 57 EXPECT_FP_EQ(nan, func(x, y, "ient)); 58 59 y = nan; 60 x = T(1.0); 61 EXPECT_FP_EQ(nan, func(x, y, "ient)); 62 63 y = T(1.0); 64 x = nan; 65 EXPECT_FP_EQ(nan, func(x, y, "ient)); 66 67 x = nan; 68 y = nan; 69 EXPECT_FP_EQ(nan, func(x, y, "ient)); 70 71 x = zero; 72 y = T(1.0); 73 EXPECT_FP_EQ(func(x, y, "ient), zero); 74 75 x = neg_zero; 76 y = T(1.0); 77 EXPECT_FP_EQ(func(x, y, "ient), neg_zero); 78 79 x = T(1.125); 80 y = inf; 81 EXPECT_FP_EQ(func(x, y, "ient), x); 82 EXPECT_EQ(quotient, 0); 83 } 84 testEqualNumeratorAndDenominator(RemQuoFunc func)85 void testEqualNumeratorAndDenominator(RemQuoFunc func) { 86 T x = T(1.125), y = T(1.125); 87 int q; 88 89 // When the remainder is zero, the standard requires it to 90 // have the same sign as x. 91 92 EXPECT_FP_EQ(func(x, y, &q), zero); 93 EXPECT_EQ(q, 1); 94 95 EXPECT_FP_EQ(func(x, -y, &q), zero); 96 EXPECT_EQ(q, -1); 97 98 EXPECT_FP_EQ(func(-x, y, &q), neg_zero); 99 EXPECT_EQ(q, -1); 100 101 EXPECT_FP_EQ(func(-x, -y, &q), neg_zero); 102 EXPECT_EQ(q, 1); 103 } 104 testSubnormalRange(RemQuoFunc func)105 void testSubnormalRange(RemQuoFunc func) { 106 constexpr StorageType COUNT = 100'001; 107 constexpr StorageType STEP = (MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT; 108 for (StorageType v = MIN_SUBNORMAL, w = MAX_SUBNORMAL; 109 v <= MAX_SUBNORMAL && w >= MIN_SUBNORMAL; v += STEP, w -= STEP) { 110 T x = FPBits(v).get_val(), y = FPBits(w).get_val(); 111 mpfr::BinaryOutput<T> result; 112 mpfr::BinaryInput<T> input{x, y}; 113 result.f = func(x, y, &result.i); 114 ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0); 115 } 116 } 117 118 void testNormalRange(RemQuoFunc func) { 119 constexpr StorageType COUNT = 1'001; 120 constexpr StorageType STEP = (MAX_NORMAL - MIN_NORMAL) / COUNT; 121 for (StorageType v = MIN_NORMAL, w = MAX_NORMAL; 122 v <= MAX_NORMAL && w >= MIN_NORMAL; v += STEP, w -= STEP) { 123 T x = FPBits(v).get_val(), y = FPBits(w).get_val(); 124 mpfr::BinaryOutput<T> result; 125 mpfr::BinaryInput<T> input{x, y}; 126 result.f = func(x, y, &result.i); 127 128 // In normal range on x86 platforms, the long double implicit 1 bit can be 129 // zero making the numbers NaN. Hence we test for them separately. 130 if (isnan(x) || isnan(y)) { 131 ASSERT_FP_EQ(result.f, nan); 132 continue; 133 } 134 135 ASSERT_MPFR_MATCH(mpfr::Operation::RemQuo, input, result, 0.0); 136 } 137 } 138 }; 139 140 #define LIST_REMQUO_TESTS(T, func) \ 141 using LlvmLibcRemQuoTest = RemQuoTestTemplate<T>; \ 142 TEST_F(LlvmLibcRemQuoTest, SpecialNumbers) { testSpecialNumbers(&func); } \ 143 TEST_F(LlvmLibcRemQuoTest, EqualNumeratorAndDenominator) { \ 144 testEqualNumeratorAndDenominator(&func); \ 145 } \ 146 TEST_F(LlvmLibcRemQuoTest, SubnormalRange) { testSubnormalRange(&func); } \ 147 TEST_F(LlvmLibcRemQuoTest, NormalRange) { testNormalRange(&func); } 148 149 #endif // LLVM_LIBC_TEST_SRC_MATH_REMQUOTEST_H 150