1//===-- Unittests for e^x - 1 ---------------------------------------------===//
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/expm1.h"
13#include "test/UnitTest/FPMatcher.h"
14#include "test/UnitTest/Test.h"
15#include "utils/MPFRWrapper/MPFRUtils.h"
16
17#include <errno.h>
18#include <stdint.h>
19
20using LlvmLibcExpm1Test = LIBC_NAMESPACE::testing::FPTest<double>;
21
22namespace mpfr = LIBC_NAMESPACE::testing::mpfr;
23using LIBC_NAMESPACE::testing::tlog;
24
25TEST_F(LlvmLibcExpm1Test, TrickyInputs) {
26 constexpr int N = 21;
27 constexpr uint64_t INPUTS[N] = {
28 0x3FD79289C6E6A5C0, // x=0x1.79289c6e6a5cp-2
29 0x3FD05DE80A173EA0, // x=0x1.05de80a173eap-2
30 0xbf1eb7a4cb841fcc, // x=-0x1.eb7a4cb841fccp-14
31 0xbf19a61fb925970d, // x=-0x1.9a61fb925970dp-14
32 0x3fda7b764e2cf47a, // x=0x1.a7b764e2cf47ap-2
33 0xc04757852a4b93aa, // x=-0x1.757852a4b93aap+5
34 0x4044c19e5712e377, // x=0x1.4c19e5712e377p+5
35 0xbf19a61fb925970d, // x=-0x1.9a61fb925970dp-14
36 0xc039a74cdab36c28, // x=-0x1.9a74cdab36c28p+4
37 0xc085b3e4e2e3bba9, // x=-0x1.5b3e4e2e3bba9p+9
38 0xc086960d591aec34, // x=-0x1.6960d591aec34p+9
39 0xc086232c09d58d91, // x=-0x1.6232c09d58d91p+9
40 0xc0874910d52d3051, // x=-0x1.74910d52d3051p9
41 0xc0867a172ceb0990, // x=-0x1.67a172ceb099p+9
42 0xc08ff80000000000, // x=-0x1.ff8p+9
43 0xbc971547652b82fe, // x=-0x1.71547652b82fep-54
44 0xbce465655f122ff6, // x=-0x1.465655f122ff6p-49
45 0x3d1bc8ee6b28659a, // x=0x1.bc8ee6b28659ap-46
46 0x3f18442b169f672d, // x=0x1.8442b169f672dp-14
47 0xc02b4f0cfb15ca0f, // x=-0x1.b4f0cfb15ca0fp+3
48 0xc042b708872320dd, // x=-0x1.2b708872320ddp+5
49 };
50 for (int i = 0; i < N; ++i) {
51 double x = FPBits(INPUTS[i]).get_val();
52 EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Expm1, x,
53 LIBC_NAMESPACE::expm1(x), 0.5);
54 }
55}
56
57TEST_F(LlvmLibcExpm1Test, InDoubleRange) {
58 constexpr uint64_t COUNT = 1'231;
59 uint64_t START = LIBC_NAMESPACE::fputil::FPBits<double>(0.25).uintval();
60 uint64_t STOP = LIBC_NAMESPACE::fputil::FPBits<double>(4.0).uintval();
61 uint64_t STEP = (STOP - START) / COUNT;
62
63 auto test = [&](mpfr::RoundingMode rounding_mode) {
64 mpfr::ForceRoundingMode __r(rounding_mode);
65 if (!__r.success)
66 return;
67
68 uint64_t fails = 0;
69 uint64_t count = 0;
70 uint64_t cc = 0;
71 double mx, mr = 0.0;
72 double tol = 0.5;
73
74 for (uint64_t i = 0, v = START; i <= COUNT; ++i, v += STEP) {
75 double x = FPBits(v).get_val();
76 if (isnan(x: x) || isinf(x: x) || x < 0.0)
77 continue;
78 LIBC_NAMESPACE::libc_errno = 0;
79 double result = LIBC_NAMESPACE::expm1(x);
80 ++cc;
81 if (isnan(x: result) || isinf(x: result))
82 continue;
83
84 ++count;
85
86 if (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Expm1, x, result,
87 0.5, rounding_mode)) {
88 ++fails;
89 while (!TEST_MPFR_MATCH_ROUNDING_SILENTLY(mpfr::Operation::Expm1, x,
90 result, tol, rounding_mode)) {
91 mx = x;
92 mr = result;
93
94 if (tol > 1000.0)
95 break;
96
97 tol *= 2.0;
98 }
99 }
100 }
101 tlog << " Expm1 failed: " << fails << "/" << count << "/" << cc
102 << " tests.\n";
103 tlog << " Max ULPs is at most: " << static_cast<uint64_t>(tol) << ".\n";
104 if (fails) {
105 EXPECT_MPFR_MATCH(mpfr::Operation::Expm1, mx, mr, 0.5, rounding_mode);
106 }
107 };
108
109 tlog << " Test Rounding To Nearest...\n";
110 test(mpfr::RoundingMode::Nearest);
111
112 tlog << " Test Rounding Downward...\n";
113 test(mpfr::RoundingMode::Downward);
114
115 tlog << " Test Rounding Upward...\n";
116 test(mpfr::RoundingMode::Upward);
117
118 tlog << " Test Rounding Toward Zero...\n";
119 test(mpfr::RoundingMode::TowardZero);
120}
121

source code of libc/test/src/math/expm1_test.cpp