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