1 //===-- Unittests for log1p -----------------------------------------------===// 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 #include "hdr/math_macros.h" 10 #include "src/__support/FPUtil/FPBits.h" 11 #include "src/errno/libc_errno.h" 12 #include "src/math/log1p.h" 13 #include "test/UnitTest/FPMatcher.h" 14 #include "test/UnitTest/Test.h" 15 #include "utils/MPFRWrapper/MPFRUtils.h" 16 17 #include <stdint.h> 18 19 using LlvmLibcLog1pTest = LIBC_NAMESPACE::testing::FPTest<double>; 20 21 namespace mpfr = LIBC_NAMESPACE::testing::mpfr; 22 using LIBC_NAMESPACE::testing::tlog; 23 24 TEST_F(LlvmLibcLog1pTest, SpecialNumbers) { 25 EXPECT_FP_EQ(aNaN, LIBC_NAMESPACE::log1p(aNaN)); 26 EXPECT_FP_EQ(inf, LIBC_NAMESPACE::log1p(inf)); 27 EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::log1p(neg_inf), FE_INVALID); 28 EXPECT_FP_IS_NAN_WITH_EXCEPTION(LIBC_NAMESPACE::log1p(-2.0), FE_INVALID); 29 EXPECT_FP_EQ(zero, LIBC_NAMESPACE::log1p(0.0)); 30 EXPECT_FP_EQ(neg_zero, LIBC_NAMESPACE::log1p(-0.0)); 31 EXPECT_FP_EQ_WITH_EXCEPTION(neg_inf, LIBC_NAMESPACE::log1p(-1.0), 32 FE_DIVBYZERO); 33 } 34 35 TEST_F(LlvmLibcLog1pTest, TrickyInputs) { 36 constexpr int N = 42; 37 constexpr uint64_t INPUTS[N] = { 38 0x3ff0000000000000, // x = 1.0 39 0x4024000000000000, // x = 10.0 40 0x4059000000000000, // x = 10^2 41 0x408f400000000000, // x = 10^3 42 0x40c3880000000000, // x = 10^4 43 0x40f86a0000000000, // x = 10^5 44 0x412e848000000000, // x = 10^6 45 0x416312d000000000, // x = 10^7 46 0x4197d78400000000, // x = 10^8 47 0x41cdcd6500000000, // x = 10^9 48 0x4202a05f20000000, // x = 10^10 49 0x42374876e8000000, // x = 10^11 50 0x426d1a94a2000000, // x = 10^12 51 0x42a2309ce5400000, // x = 10^13 52 0x42d6bcc41e900000, // x = 10^14 53 0x430c6bf526340000, // x = 10^15 54 0x4341c37937e08000, // x = 10^16 55 0x4376345785d8a000, // x = 10^17 56 0x43abc16d674ec800, // x = 10^18 57 0x43e158e460913d00, // x = 10^19 58 0x4415af1d78b58c40, // x = 10^20 59 0x444b1ae4d6e2ef50, // x = 10^21 60 0x4480f0cf064dd592, // x = 10^22 61 0x3fefffffffef06ad, 0x3fefde0f22c7d0eb, 0x225e7812faadb32f, 62 0x3fee1076964c2903, 0x3fdfe93fff7fceb0, 0x3ff012631ad8df10, 63 0x3fefbfdaa448ed98, 0x3fd00a8cefe9a5f8, 0x3fd0b4d870eb22f8, 64 0x3c90c40cef04efb5, 0x449d2ccad399848e, 0x4aa12ccdffd9d2ec, 65 0x5656f070b92d36ce, 0x6db06dcb74f76bcc, 0x7f1954e72ffd4596, 66 0x5671e2f1628093e4, 0x73dac56e2bf1a951, 0x8001bc6879ea14c5, 67 0x45ca5f497ec291df, // x = 0x1.a5f497ec291dfp+93 68 }; 69 for (int i = 0; i < N; ++i) { 70 double x = FPBits(INPUTS[i]).get_val(); 71 EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log1p, x, 72 LIBC_NAMESPACE::log1p(x), 0.5); 73 } 74 } 75 76 TEST_F(LlvmLibcLog1pTest, AllExponents) { 77 double x = 0x1.0p-1074; 78 for (int i = -1074; i < 1024; ++i, x *= 2.0) { 79 ASSERT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Log1p, x, 80 LIBC_NAMESPACE::log1p(x), 0.5); 81 } 82 } 83 84 TEST_F(LlvmLibcLog1pTest, InDoubleRange) { 85 constexpr uint64_t COUNT = 4501; 86 87 auto test = [&](uint64_t start, uint64_t stop, 88 mpfr::RoundingMode rounding_mode) { 89 mpfr::ForceRoundingMode __r(rounding_mode); 90 if (!__r.success) 91 return; 92 93 uint64_t fails = 0; 94 uint64_t count = 0; 95 uint64_t cc = 0; 96 double mx, mr = 0.0; 97 double tol = 0.5; 98 99 uint64_t step = (stop - start) / COUNT; 100 101 for (uint64_t i = 0, v = start; i <= COUNT; ++i, v += step) { 102 double x = FPBits(v).get_val(); 103 if (FPBits(v).is_nan() || FPBits(v).is_inf() || x < 0.0) 104 continue; 105 LIBC_NAMESPACE::libc_errno = 0; 106 double result = LIBC_NAMESPACE::log1p(x); 107 ++cc; 108 if (FPBits(result).is_nan() || FPBits(result).is_inf()) 109 continue; 110 111 ++count; 112 // ASSERT_MPFR_MATCH(mpfr::Operation::Log1p, x, result, 0.5); 113 if (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Log1p, x, result, 114 0.5, rounding_mode)) { 115 ++fails; 116 while (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Log1p, x, 117 result, tol, rounding_mode)) { 118 mx = x; 119 mr = result; 120 tol *= 2.0; 121 } 122 } 123 } 124 tlog << " Log1p failed: " << fails << "/" << count << "/" << cc 125 << " tests.\n"; 126 tlog << " Max ULPs is at most: " << static_cast<uint64_t>(tol) << ".\n"; 127 if (fails) { 128 EXPECT_MPFR_MATCH(mpfr::Operation::Log1p, mx, mr, 0.5, rounding_mode); 129 } 130 }; 131 132 auto test_all_rounding = [&](uint64_t start, uint64_t stop, 133 const char *start_str, const char *stop_str) { 134 tlog << "\n=== Test in range [" << start_str << ", " << stop_str 135 << "] ===\n"; 136 137 tlog << "\n Test Rounding To Nearest...\n"; 138 test(start, stop, mpfr::RoundingMode::Nearest); 139 140 tlog << "\n Test Rounding Downward...\n"; 141 test(start, stop, mpfr::RoundingMode::Downward); 142 143 tlog << "\n Test Rounding Upward...\n"; 144 test(start, stop, mpfr::RoundingMode::Upward); 145 146 tlog << "\n Test Rounding Toward Zero...\n"; 147 test(start, stop, mpfr::RoundingMode::TowardZero); 148 }; 149 150 test_all_rounding(0x0000'0000'0000'0001ULL, 0x0010'0000'0000'0000ULL, 151 "2^-1074", "2^-1022"); 152 153 test_all_rounding(0x39B0'0000'0000'0000ULL, 0x3A50'0000'0000'0000ULL, 154 "2^-100", "2^-90"); 155 156 test_all_rounding(0x3CD0'0000'0000'0000ULL, 0x3D20'0000'0000'0000ULL, "2^-50", 157 "2^-45"); 158 159 test_all_rounding(0x3E10'0000'0000'0000ULL, 0x3E40'0000'0000'0000ULL, "2^-30", 160 "2^-27"); 161 162 test_all_rounding(0x3FD0'0000'0000'0000ULL, 0x4010'0000'0000'0000ULL, "0.25", 163 "4.0"); 164 165 test_all_rounding(0x4630'0000'0000'0000ULL, 0x4670'0000'0000'0000ULL, "2^100", 166 "2^104"); 167 168 test_all_rounding(0x7FD0'0000'0000'0000ULL, 0x7FF0'0000'0000'0000ULL, 169 "2^1022", "2^1024"); 170 } 171