1 | //===-- Utility class to test integer sqrt ----------------------*- 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 | #include "test/UnitTest/FPMatcher.h" |
10 | #include "test/UnitTest/Test.h" |
11 | |
12 | #include "src/__support/CPP/bit.h" |
13 | #include "src/__support/FPUtil/BasicOperations.h" |
14 | #include "src/__support/fixed_point/fx_rep.h" |
15 | #include "src/__support/fixed_point/sqrt.h" |
16 | |
17 | #include "src/math/exp.h" |
18 | |
19 | template <typename T> class ExpTest : public LIBC_NAMESPACE::testing::Test { |
20 | |
21 | using FXRep = LIBC_NAMESPACE::fixed_point::FXRep<T>; |
22 | static constexpr T zero = FXRep::ZERO(); |
23 | static constexpr T one = static_cast<T>(1); |
24 | static constexpr T eps = FXRep::EPS(); |
25 | |
26 | public: |
27 | typedef T (*ExpFunc)(T); |
28 | |
29 | void test_special_numbers(ExpFunc func) { |
30 | EXPECT_EQ(one, func(T(0))); |
31 | EXPECT_EQ(FXRep::MAX(), func(T(30))); |
32 | EXPECT_EQ(zero, func(T(-30))); |
33 | } |
34 | |
35 | void test_range_with_step(ExpFunc func, T step, bool rel_error) { |
36 | constexpr int COUNT = 255; |
37 | constexpr double ERR = 3.0 * static_cast<double>(eps); |
38 | double x_d = 0.0; |
39 | T x = step; |
40 | for (int i = 0; i < COUNT; ++i) { |
41 | x += step; |
42 | x_d = static_cast<double>(x); |
43 | double y_d = static_cast<double>(func(x)); |
44 | double result = LIBC_NAMESPACE::exp(x: x_d); |
45 | double errors = rel_error |
46 | ? LIBC_NAMESPACE::fputil::abs(x: (y_d / result) - 1.0) |
47 | : LIBC_NAMESPACE::fputil::abs(x: y_d - result); |
48 | if (errors > ERR) { |
49 | // Print out the failure input and output. |
50 | EXPECT_EQ(x, T(0)); |
51 | EXPECT_EQ(func(x), zero); |
52 | } |
53 | ASSERT_TRUE(errors <= ERR); |
54 | } |
55 | } |
56 | |
57 | void test_positive_range(ExpFunc func) { |
58 | test_range_with_step(func, step: T(0x1.0p-6), /*rel_error*/ rel_error: true); |
59 | } |
60 | |
61 | void test_negative_range(ExpFunc func) { |
62 | test_range_with_step(func, step: T(-0x1.0p-6), /*rel_error*/ rel_error: false); |
63 | } |
64 | }; |
65 | |
66 | #define LIST_EXP_TESTS(Name, T, func) \ |
67 | using LlvmLibcExp##Name##Test = ExpTest<T>; \ |
68 | TEST_F(LlvmLibcExp##Name##Test, SpecialNumbers) { \ |
69 | test_special_numbers(&func); \ |
70 | } \ |
71 | TEST_F(LlvmLibcExp##Name##Test, PositiveRange) { \ |
72 | test_positive_range(&func); \ |
73 | } \ |
74 | TEST_F(LlvmLibcExp##Name##Test, NegativeRange) { \ |
75 | test_negative_range(&func); \ |
76 | } \ |
77 | static_assert(true, "Require semicolon.") |
78 | |