xref: /aosp_15_r20/external/llvm-libc/test/src/math/smoke/NextTowardTest.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1 //===-- Utility class to test different flavors of nexttoward ---*- 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 #ifndef LLVM_LIBC_TEST_SRC_MATH_NEXTTOWARDTEST_H
10 #define LLVM_LIBC_TEST_SRC_MATH_NEXTTOWARDTEST_H
11 
12 #include "src/__support/CPP/bit.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 
19 #include "hdr/fenv_macros.h"
20 
21 using LIBC_NAMESPACE::Sign;
22 
23 // TODO: Strengthen errno,exception checks and remove these assert macros
24 // after new matchers/test fixtures are added
25 #define ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, expected_exception)      \
26   ASSERT_FP_EQ(result, expected);                                              \
27   ASSERT_FP_EXCEPTION(expected_exception);                                     \
28   LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT)
29 
30 #define ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected)                          \
31   ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, FE_INEXACT | FE_UNDERFLOW)
32 
33 #define ASSERT_FP_EQ_WITH_OVERFLOW(result, expected)                           \
34   ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, FE_INEXACT | FE_OVERFLOW)
35 
36 template <typename T>
37 class NextTowardTestTemplate : public LIBC_NAMESPACE::testing::FEnvSafeTest {
38   using FPBits = LIBC_NAMESPACE::fputil::FPBits<T>;
39   using ToFPBits = LIBC_NAMESPACE::fputil::FPBits<long double>;
40   using StorageType = typename FPBits::StorageType;
41 
42   const T inf = FPBits::inf(Sign::POS).get_val();
43   const T neg_inf = FPBits::inf(Sign::NEG).get_val();
44   const T zero = FPBits::zero(Sign::POS).get_val();
45   const T neg_zero = FPBits::zero(Sign::NEG).get_val();
46   const T nan = FPBits::quiet_nan().get_val();
47 
48   const long double to_inf = ToFPBits::inf(Sign::POS).get_val();
49   const long double to_neg_inf = ToFPBits::inf(Sign::NEG).get_val();
50   const long double to_zero = ToFPBits::zero().get_val();
51   const long double to_neg_zero = ToFPBits::zero(Sign::NEG).get_val();
52   const long double to_nan = ToFPBits::quiet_nan().get_val();
53 
54   static constexpr StorageType min_subnormal =
55       FPBits::min_subnormal().uintval();
56   static constexpr StorageType max_subnormal =
57       FPBits::max_subnormal().uintval();
58   static constexpr StorageType min_normal = FPBits::min_normal().uintval();
59   static constexpr StorageType max_normal = FPBits::max_normal().uintval();
60 
61 public:
62   typedef T (*NextTowardFunc)(T, long double);
63 
testNaN(NextTowardFunc func)64   void testNaN(NextTowardFunc func) {
65     ASSERT_FP_EQ(func(nan, 0), nan);
66     ASSERT_FP_EQ(func(0, to_nan), nan);
67   }
68 
testBoundaries(NextTowardFunc func)69   void testBoundaries(NextTowardFunc func) {
70     ASSERT_FP_EQ(func(zero, to_neg_zero), neg_zero);
71     ASSERT_FP_EQ(func(neg_zero, to_zero), zero);
72 
73     // 'from' is zero|neg_zero.
74     T x = zero;
75     T result = func(x, 1);
76     StorageType expected_bits = 1;
77     T expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
78     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
79 
80     result = func(x, -1);
81     expected_bits = FPBits::SIGN_MASK + 1;
82     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
83     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
84 
85     x = neg_zero;
86     result = func(x, 1);
87     expected_bits = 1;
88     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
89     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
90 
91     result = func(x, -1);
92     expected_bits = FPBits::SIGN_MASK + 1;
93     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
94     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
95 
96     // 'from' is max subnormal value.
97     x = LIBC_NAMESPACE::cpp::bit_cast<T>(max_subnormal);
98     result = func(x, 1);
99     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(min_normal);
100     ASSERT_FP_EQ(result, expected);
101 
102     result = func(x, 0);
103     expected_bits = max_subnormal - 1;
104     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
105     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
106 
107     x = -x;
108 
109     result = func(x, -1);
110     expected_bits = FPBits::SIGN_MASK + min_normal;
111     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
112     ASSERT_FP_EQ(result, expected);
113 
114     result = func(x, 0);
115     expected_bits = FPBits::SIGN_MASK + max_subnormal - 1;
116     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
117     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
118 
119     // 'from' is min subnormal value.
120     x = LIBC_NAMESPACE::cpp::bit_cast<T>(min_subnormal);
121     result = func(x, 1);
122     expected_bits = min_subnormal + 1;
123     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
124     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
125     ASSERT_FP_EQ_WITH_UNDERFLOW(func(x, 0), 0);
126 
127     x = -x;
128     result = func(x, -1);
129     expected_bits = FPBits::SIGN_MASK + min_subnormal + 1;
130     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
131     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
132     ASSERT_FP_EQ_WITH_UNDERFLOW(func(x, 0), T(-0.0));
133 
134     // 'from' is min normal.
135     x = LIBC_NAMESPACE::cpp::bit_cast<T>(min_normal);
136     result = func(x, 0);
137     expected_bits = max_subnormal;
138     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
139     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
140 
141     result = func(x, to_inf);
142     expected_bits = min_normal + 1;
143     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
144     ASSERT_FP_EQ(result, expected);
145 
146     x = -x;
147     result = func(x, 0);
148     expected_bits = FPBits::SIGN_MASK + max_subnormal;
149     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
150     ASSERT_FP_EQ_WITH_UNDERFLOW(result, expected);
151 
152     result = func(x, to_neg_inf);
153     expected_bits = FPBits::SIGN_MASK + min_normal + 1;
154     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
155     ASSERT_FP_EQ(result, expected);
156 
157     // 'from' is max normal
158     x = LIBC_NAMESPACE::cpp::bit_cast<T>(max_normal);
159     result = func(x, 0);
160     expected_bits = max_normal - 1;
161     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
162     ASSERT_FP_EQ(result, expected);
163     ASSERT_FP_EQ_WITH_OVERFLOW(func(x, to_inf), inf);
164 
165     x = -x;
166     result = func(x, 0);
167     expected_bits = FPBits::SIGN_MASK + max_normal - 1;
168     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
169     ASSERT_FP_EQ(result, expected);
170     ASSERT_FP_EQ_WITH_OVERFLOW(func(x, to_neg_inf), neg_inf);
171 
172     // 'from' is infinity.
173     x = inf;
174     result = func(x, 0);
175     expected_bits = max_normal;
176     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
177     ASSERT_FP_EQ(result, expected);
178     ASSERT_FP_EQ(func(x, to_inf), inf);
179 
180     x = neg_inf;
181     result = func(x, 0);
182     expected_bits = FPBits::SIGN_MASK + max_normal;
183     expected = LIBC_NAMESPACE::cpp::bit_cast<T>(expected_bits);
184     ASSERT_FP_EQ(result, expected);
185     ASSERT_FP_EQ(func(x, to_neg_inf), neg_inf);
186 
187     // 'from' is a power of 2.
188     x = T(32.0);
189     result = func(x, 0);
190     FPBits x_bits = FPBits(x);
191     FPBits result_bits = FPBits(result);
192     ASSERT_EQ(result_bits.get_biased_exponent(),
193               uint16_t(x_bits.get_biased_exponent() - 1));
194     ASSERT_EQ(result_bits.get_mantissa(), FPBits::FRACTION_MASK);
195 
196     result = func(x, 33.0);
197     result_bits = FPBits(result);
198     ASSERT_EQ(result_bits.get_biased_exponent(), x_bits.get_biased_exponent());
199     ASSERT_EQ(result_bits.get_mantissa(),
200               static_cast<StorageType>(x_bits.get_mantissa() + StorageType(1)));
201 
202     x = -x;
203 
204     result = func(x, 0);
205     result_bits = FPBits(result);
206     ASSERT_EQ(result_bits.get_biased_exponent(),
207               uint16_t(x_bits.get_biased_exponent() - 1));
208     ASSERT_EQ(result_bits.get_mantissa(), FPBits::FRACTION_MASK);
209 
210     result = func(x, -33.0);
211     result_bits = FPBits(result);
212     ASSERT_EQ(result_bits.get_biased_exponent(), x_bits.get_biased_exponent());
213     ASSERT_EQ(result_bits.get_mantissa(),
214               static_cast<StorageType>(x_bits.get_mantissa() + StorageType(1)));
215   }
216 };
217 
218 #define LIST_NEXTTOWARD_TESTS(T, func)                                         \
219   using LlvmLibcNextTowardTest = NextTowardTestTemplate<T>;                    \
220   TEST_F(LlvmLibcNextTowardTest, TestNaN) { testNaN(&func); }                  \
221   TEST_F(LlvmLibcNextTowardTest, TestBoundaries) { testBoundaries(&func); }
222 
223 #endif // LLVM_LIBC_TEST_SRC_MATH_NEXTTOWARDTEST_H
224