1 /***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay, Wolf Vollprecht and *
3 * Martin Renou *
4 * Copyright (c) QuantStack *
5 * *
6 * Distributed under the terms of the BSD 3-Clause License. *
7 * *
8 * The full license is in the file LICENSE, distributed with this software. *
9 ****************************************************************************/
10
11 #include "test_utils.hpp"
12
13 namespace xsimd
14 {
15 template <class T>
16 struct test_int_min_max
17 {
runxsimd::test_int_min_max18 bool run()
19 {
20 return true;
21 }
22 };
23
24 template <class T>
25 struct test_int_min_max<batch<T, 2>>
26 {
runxsimd::test_int_min_max27 void run()
28 {
29 using B = batch<T, 2>;
30 using BB = batch_bool<T, 2>;
31 using A = std::array<T, 2>;
32
33 T max = std::numeric_limits<T>::max();
34 T min = std::numeric_limits<T>::min();
35 std::array<T, 2> maxmin_cmp{{max, min}};
36 B maxmin(max, min);
37 EXPECT_BATCH_EQ(maxmin, maxmin_cmp) << print_function_name("numeric max and min");
38
39 B a(1, 3);
40 B b(2);
41 B c(2, 3);
42
43 auto r1 = xsimd::max(a, c);
44 auto r3 = xsimd::min(a, c);
45
46 EXPECT_BATCH_EQ(r1, (A{{2, 3}})) << print_function_name("max");
47 EXPECT_BATCH_EQ(r3, (A{{1, 3}})) << print_function_name("min");
48
49 auto r4 = a < b; // test lt
50 BB e4(1, 0);
51 EXPECT_TRUE(xsimd::all(r4 == e4));
52 }
53 };
54
55 template <class T>
56 struct test_int_min_max<batch<T, 4>>
57 {
runxsimd::test_int_min_max58 void run()
59 {
60 using B = batch<T, 4>;
61 using BB = batch_bool<T, 4>;
62 using A = std::array<T, 4>;
63
64 B a(1,3,1,1);
65 B b(2);
66 B c(2,3,2,3);
67
68 auto r1 = xsimd::max(a, c);
69 auto r3 = xsimd::min(a, c);
70
71 EXPECT_BATCH_EQ(r1, (A{{2, 3, 2, 3}})) << print_function_name("max");
72 EXPECT_BATCH_EQ(r3, (A{{1, 3, 1, 1}})) << print_function_name("min");
73
74 auto r4 = a < b; // test lt
75 BB e4(1,0,1,1);
76 EXPECT_TRUE(xsimd::all(r4 == e4));
77 }
78 };
79
80 template <class T>
81 struct test_int_min_max<batch<T, 8>>
82 {
runxsimd::test_int_min_max83 void run()
84 {
85 using B = batch<T, 8>;
86 using BB = batch_bool<T, 8>;
87 using A = std::array<T, 8>;
88
89 T max = std::numeric_limits<T>::max();
90 T min = std::numeric_limits<T>::min();
91 std::array<T, 8> maxmin_cmp{{0, 0, max, 0, min, 0, 0, 0}};
92 B maxmin(0, 0, max, 0, min, 0, 0, 0);
93 EXPECT_BATCH_EQ(maxmin, maxmin_cmp) << print_function_name("numeric max and min");
94
95 B a(1,3,1,3, 1,1,3,3);
96 B b(2);
97 B c(2,3,2,3, 2,3,2,3);
98
99 auto r1 = xsimd::max(a, c);
100 auto r3 = xsimd::min(a, c);
101 auto r4 = a < b; // test lt
102 EXPECT_BATCH_EQ(r1, (A{{2, 3, 2, 3, 2, 3, 3, 3}})) << print_function_name("max");
103 EXPECT_BATCH_EQ(r3, (A{{1, 3, 1, 3, 1, 1, 2, 3}})) << print_function_name("min");
104
105 BB e4(1,0,1,0, 1,1,0,0);
106 EXPECT_TRUE(xsimd::all(r4 == e4));
107 }
108 };
109
110 template <class T>
111 struct test_int_min_max<batch<T, 16>>
112 {
runxsimd::test_int_min_max113 void run()
114 {
115 using B = batch<T, 16>;
116 using BB = batch_bool<T, 16>;
117 using A = std::array<T, 16>;
118
119 T max = std::numeric_limits<T>::max();
120 T min = std::numeric_limits<T>::min();
121 std::array<T, 16> maxmin_cmp{{0, 0, max, 0, min, 0, 0, 0, 0, 0, max, 0, min, 0, 0, 0}};
122 B maxmin(0, 0, max, 0, min, 0, 0, 0, 0, 0, max, 0, min, 0, 0, 0);
123 EXPECT_BATCH_EQ(maxmin, maxmin_cmp) << print_function_name("numeric max and min");
124
125 B a(1,3,1,3, 1,3,1,3, 3,3,3,3, min,max,max,min);
126 B b(2);
127 B c(2,3,2,3, 2,3,2,3, 2,3,2,3, 2,3,2,3);
128 auto r1 = xsimd::max(a, b);
129 auto r3 = xsimd::min(a, b);
130 auto r4 = a < b; // test lt
131 auto r5 = a == c;
132 auto r6 = a != c;
133
134 EXPECT_BATCH_EQ(r1, (A{{2,3,2,3, 2,3,2,3, 3,3,3,3, 2,max,max,2}})) << print_function_name("max");
135 EXPECT_BATCH_EQ(r3, (A{{1,2,1,2, 1,2,1,2, 2,2,2,2, min,2,2,min}})) << print_function_name("min");
136
137 BB e4(1,0,1,0, 1,0,1,0, 0,0,0,0, 1,0,0,1);
138 EXPECT_TRUE(xsimd::all(r4 == e4));
139
140 BB e5(0,1,0,1, 0,1,0,1, 0,1,0,1, 0,0,0,0);
141 EXPECT_TRUE(xsimd::all(r5 == e5));
142 EXPECT_TRUE(xsimd::all(r6 == !e5));
143 }
144 };
145
146 template <class T>
147 struct test_int_min_max<batch<T, 32>>
148 {
runxsimd::test_int_min_max149 void run()
150 {
151 using B = batch<T, 32>;
152 using BB = batch_bool<T, 32>;
153 using A = std::array<T, 32>;
154 T max = std::numeric_limits<T>::max();
155 T min = std::numeric_limits<T>::min();
156
157 B a(1,3,1,3, 1,3,1,3, 1,3,1,3, 1,3,1,3, 1,3,1,3, 1,3,1,3, 3,3,3,3, min,max,max,min);
158 B b(2);
159 B c(2,3,2,3, 2,3,2,3, 2,3,2,3, 2,3,2,3, 2,3,2,3, 2,3,2,3, 2,3,2,3, 2,3,2,3);
160
161 auto r1 = xsimd::max(a, b);
162 auto r3 = xsimd::min(a, b);
163 auto r4 = a < b; // test lt
164 EXPECT_BATCH_EQ(r1, (A{{2,3,2,3, 2,3,2,3, 2,3,2,3, 2,3,2,3, 2,3,2,3, 2,3,2,3, 3,3,3,3, 2,max,max,2}})) << print_function_name("max");
165 EXPECT_BATCH_EQ(r3, (A{{1,2,1,2, 1,2,1,2, 1,2,1,2, 1,2,1,2, 1,2,1,2, 1,2,1,2, 2,2,2,2, min,2,2,min}})) << print_function_name("min");
166
167 BB e4(1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0, 1,0,1,0, 0,0,0,0, 1,0,0,1);
168 EXPECT_TRUE(xsimd::all(r4 == e4));
169 }
170 };
171 }
172
173 template <class B>
174 class batch_int_test : public testing::Test
175 {
176 protected:
177
178 using batch_type = B;
179 using value_type = typename B::value_type;
180 static constexpr size_t size = B::size;
181 using array_type = std::array<value_type, size>;
182 using bool_array_type = std::array<bool, size>;
183
184 array_type lhs;
185 array_type rhs;
186 array_type shift;
187
batch_int_test()188 batch_int_test()
189 {
190 using signed_value_type = typename std::make_signed<value_type>::type;
191 for (size_t i = 0; i < size; ++i)
192 {
193 bool negative_lhs = std::is_signed<value_type>::value && (i % 2 == 1);
194 lhs[i] = value_type(i) * (negative_lhs ? -10 : 10);
195 if (lhs[i] == value_type(0))
196 {
197 lhs[i] += value_type(1);
198 }
199 rhs[i] = value_type(i) + value_type(4);
200 shift[i] = signed_value_type(i) % (CHAR_BIT * sizeof(value_type));
201 }
202 }
203
test_modulo() const204 void test_modulo() const
205 {
206 // batch % batch
207 {
208 array_type expected;
209 std::transform(lhs.cbegin(), lhs.cend(), rhs.cbegin(), expected.begin(),
210 [](const value_type& l, const value_type& r) { return l % r; });
211 batch_type res = batch_lhs() % batch_rhs();
212 EXPECT_BATCH_EQ(res, expected) << print_function_name("batch % batch");
213 }
214 }
215
test_shift() const216 void test_shift() const
217 {
218 int32_t nb_sh = 3;
219 // batch << scalar
220 {
221 array_type expected;
222 std::transform(lhs.cbegin(), lhs.cend(), expected.begin(),
223 [nb_sh](const value_type& v) { return v << nb_sh; });
224 batch_type res = batch_lhs() << nb_sh;
225 EXPECT_BATCH_EQ(res, expected) << print_function_name("batch << scalar");
226 }
227 // batch << batch
228 {
229 array_type expected;
230 std::transform(lhs.cbegin(), lhs.cend(), shift.cbegin(), expected.begin(),
231 [](const value_type& l, const value_type& r) { return l << r; });
232 batch_type res = batch_lhs() << batch_shift();
233 EXPECT_BATCH_EQ(res, expected) << print_function_name("batch << batch");
234 }
235 // batch >> scalar
236 {
237 array_type expected;
238 std::transform(lhs.cbegin(), lhs.cend(), expected.begin(),
239 [nb_sh](const value_type& v) { return v >> nb_sh; });
240 batch_type res = batch_lhs() >> nb_sh;
241 EXPECT_BATCH_EQ(res, expected) << print_function_name("batch >> scalar");
242 }
243 // batch >> batch
244 {
245 array_type expected;
246 std::transform(lhs.cbegin(), lhs.cend(), shift.cbegin(), expected.begin(),
247 [](const value_type& l, const value_type& r) { return l >> r; });
248 batch_type res = batch_lhs() >> batch_shift();
249 EXPECT_BATCH_EQ(res, expected) << print_function_name("batch >> batch");
250 }
251 }
252
test_more_shift() const253 void test_more_shift() const
254 {
255 int32_t s = static_cast<int32_t>(sizeof(value_type) * 8);
256 batch_type lhs = batch_type(value_type(1));
257 batch_type res;
258
259 for (int32_t i = 0; i < s; ++i)
260 {
261 res = lhs << i;
262 value_type expected = value_type(1) << i;
263 for (std::size_t j = 0; j < size; ++j)
264 {
265 EXPECT_EQ(res[j], expected);
266 }
267 }
268 lhs = batch_type(std::numeric_limits<value_type>::max());
269 for (int32_t i = 0; i < s; ++i)
270 {
271 res = lhs >> value_type(i);
272 value_type expected = std::numeric_limits<value_type>::max() >> i;
273 for (std::size_t j = 0; j < size; ++j)
274 {
275 EXPECT_EQ(res[j], expected);
276 }
277 }
278 }
279
test_min_max() const280 void test_min_max() const
281 {
282 xsimd::test_int_min_max<batch_type> t;
283 t.run();
284 }
285
test_less_than_underflow() const286 void test_less_than_underflow() const
287 {
288 batch_type test_negative_compare = batch_type(5) - 6;
289 if (std::is_unsigned<value_type>::value)
290 {
291 EXPECT_FALSE(xsimd::any(test_negative_compare < 1));
292 }
293 else
294 {
295 EXPECT_TRUE(xsimd::all(test_negative_compare < 1));
296 }
297 }
298
299 private:
300
batch_lhs() const301 batch_type batch_lhs() const
302 {
303 return batch_type(lhs.data());
304 }
305
batch_rhs() const306 batch_type batch_rhs() const
307 {
308 return batch_type(rhs.data());
309 }
310
batch_shift() const311 batch_type batch_shift() const
312 {
313 return batch_type(shift.data());
314 }
315 };
316
317 TYPED_TEST_SUITE(batch_int_test, batch_int_types, simd_test_names);
318
TYPED_TEST(batch_int_test,modulo)319 TYPED_TEST(batch_int_test, modulo)
320 {
321 this->test_modulo();
322 }
323
TYPED_TEST(batch_int_test,shift)324 TYPED_TEST(batch_int_test, shift)
325 {
326 this->test_shift();
327 }
328
TYPED_TEST(batch_int_test,more_shift)329 TYPED_TEST(batch_int_test, more_shift)
330 {
331 this->test_more_shift();
332 }
333
TYPED_TEST(batch_int_test,min_max)334 TYPED_TEST(batch_int_test, min_max)
335 {
336 this->test_min_max();
337 }
338
TYPED_TEST(batch_int_test,less_than_underflow)339 TYPED_TEST(batch_int_test, less_than_underflow)
340 {
341 this->test_less_than_underflow();
342 }
343
344