150 lines · c
1//===-- Utility class to test different flavors of rint ---------*- 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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H10#define LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H11 12#include "src/__support/CPP/algorithm.h"13#include "src/__support/FPUtil/FEnvImpl.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#include "hdr/fenv_macros.h"21#include "hdr/math_macros.h"22 23namespace mpfr = LIBC_NAMESPACE::testing::mpfr;24using LIBC_NAMESPACE::Sign;25 26static constexpr int ROUNDING_MODES[4] = {FE_UPWARD, FE_DOWNWARD, FE_TOWARDZERO,27 FE_TONEAREST};28 29template <typename T>30class RIntTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {31public:32 typedef T (*RIntFunc)(T);33 34private:35 using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;36 using StorageType = typename FPBits::StorageType;37 38 const T inf = FPBits::inf(Sign::POS).get_val();39 const T neg_inf = FPBits::inf(Sign::NEG).get_val();40 const T zero = FPBits::zero(Sign::POS).get_val();41 const T neg_zero = FPBits::zero(Sign::NEG).get_val();42 const T nan = FPBits::quiet_nan().get_val();43 44 static constexpr StorageType MIN_SUBNORMAL =45 FPBits::min_subnormal().uintval();46 static constexpr StorageType MAX_SUBNORMAL =47 FPBits::max_subnormal().uintval();48 static constexpr StorageType MIN_NORMAL = FPBits::min_normal().uintval();49 static constexpr StorageType MAX_NORMAL = FPBits::max_normal().uintval();50 51 static inline mpfr::RoundingMode to_mpfr_rounding_mode(int mode) {52 switch (mode) {53 case FE_UPWARD:54 return mpfr::RoundingMode::Upward;55 case FE_DOWNWARD:56 return mpfr::RoundingMode::Downward;57 case FE_TOWARDZERO:58 return mpfr::RoundingMode::TowardZero;59 case FE_TONEAREST:60 return mpfr::RoundingMode::Nearest;61 default:62 __builtin_unreachable();63 }64 }65 66public:67 void testSpecialNumbers(RIntFunc func) {68 for (int mode : ROUNDING_MODES) {69 LIBC_NAMESPACE::fputil::set_round(mode);70 ASSERT_FP_EQ(inf, func(inf));71 ASSERT_FP_EQ(neg_inf, func(neg_inf));72 ASSERT_FP_EQ(nan, func(nan));73 ASSERT_FP_EQ(zero, func(zero));74 ASSERT_FP_EQ(neg_zero, func(neg_zero));75 }76 }77 78 void testRoundNumbers(RIntFunc func) {79 for (int mode : ROUNDING_MODES) {80 LIBC_NAMESPACE::fputil::set_round(mode);81 mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode);82 ASSERT_FP_EQ(func(T(1.0)), mpfr::round(T(1.0), mpfr_mode));83 ASSERT_FP_EQ(func(T(-1.0)), mpfr::round(T(-1.0), mpfr_mode));84 ASSERT_FP_EQ(func(T(10.0)), mpfr::round(T(10.0), mpfr_mode));85 ASSERT_FP_EQ(func(T(-10.0)), mpfr::round(T(-10.0), mpfr_mode));86 ASSERT_FP_EQ(func(T(1234.0)), mpfr::round(T(1234.0), mpfr_mode));87 ASSERT_FP_EQ(func(T(-1234.0)), mpfr::round(T(-1234.0), mpfr_mode));88 }89 }90 91 void testFractions(RIntFunc func) {92 for (int mode : ROUNDING_MODES) {93 LIBC_NAMESPACE::fputil::set_round(mode);94 mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode);95 ASSERT_FP_EQ(func(T(0.5)), mpfr::round(T(0.5), mpfr_mode));96 ASSERT_FP_EQ(func(T(-0.5)), mpfr::round(T(-0.5), mpfr_mode));97 ASSERT_FP_EQ(func(T(0.115)), mpfr::round(T(0.115), mpfr_mode));98 ASSERT_FP_EQ(func(T(-0.115)), mpfr::round(T(-0.115), mpfr_mode));99 ASSERT_FP_EQ(func(T(0.715)), mpfr::round(T(0.715), mpfr_mode));100 ASSERT_FP_EQ(func(T(-0.715)), mpfr::round(T(-0.715), mpfr_mode));101 }102 }103 104 void testSubnormalRange(RIntFunc func) {105 constexpr int COUNT = 100'001;106 constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max(107 static_cast<StorageType>((MAX_SUBNORMAL - MIN_SUBNORMAL) / COUNT),108 StorageType(1));109 for (StorageType i = MIN_SUBNORMAL; i <= MAX_SUBNORMAL; i += STEP) {110 T x = FPBits(i).get_val();111 for (int mode : ROUNDING_MODES) {112 LIBC_NAMESPACE::fputil::set_round(mode);113 mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode);114 ASSERT_FP_EQ(func(x), mpfr::round(x, mpfr_mode));115 }116 }117 }118 119 void testNormalRange(RIntFunc func) {120 constexpr int COUNT = 100'001;121 constexpr StorageType STEP = LIBC_NAMESPACE::cpp::max(122 static_cast<StorageType>((MAX_NORMAL - MIN_NORMAL) / COUNT),123 StorageType(1));124 for (StorageType i = MIN_NORMAL; i <= MAX_NORMAL; i += STEP) {125 FPBits xbits(i);126 T x = xbits.get_val();127 // In normal range on x86 platforms, the long double implicit 1 bit can be128 // zero making the numbers NaN. We will skip them.129 if (xbits.is_nan())130 continue;131 132 for (int mode : ROUNDING_MODES) {133 LIBC_NAMESPACE::fputil::set_round(mode);134 mpfr::RoundingMode mpfr_mode = to_mpfr_rounding_mode(mode);135 ASSERT_FP_EQ(func(x), mpfr::round(x, mpfr_mode));136 }137 }138 }139};140 141#define LIST_RINT_TESTS(F, func) \142 using LlvmLibcRIntTest = RIntTestTemplate<F>; \143 TEST_F(LlvmLibcRIntTest, specialNumbers) { testSpecialNumbers(&func); } \144 TEST_F(LlvmLibcRIntTest, RoundNumbers) { testRoundNumbers(&func); } \145 TEST_F(LlvmLibcRIntTest, Fractions) { testFractions(&func); } \146 TEST_F(LlvmLibcRIntTest, SubnormalRange) { testSubnormalRange(&func); } \147 TEST_F(LlvmLibcRIntTest, NormalRange) { testNormalRange(&func); }148 149#endif // LLVM_LIBC_TEST_SRC_MATH_RINTTEST_H150