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
21using 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
36template <typename T>
37class 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
61public:
62 typedef T (*NextTowardFunc)(T, long double);
63
64 void testNaN(NextTowardFunc func) {
65 ASSERT_FP_EQ(func(nan, 0), nan);
66 ASSERT_FP_EQ(func(0, to_nan), nan);
67 }
68
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), zero);
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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of libc/test/src/math/smoke/NextTowardTest.h