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