ROOT  6.06/09
Reference Guide
arithmetics.cpp
Go to the documentation of this file.
1 /* This file is part of the Vc library.
2 
3  Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
4 
5  Vc is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as
7  published by the Free Software Foundation, either version 3 of
8  the License, or (at your option) any later version.
9 
10  Vc is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with Vc. If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 
20 #include "unittest.h"
21 #include <iostream>
22 #include <limits>
23 #include <Vc/limits>
24 #include <Vc/common/macros.h>
25 
26 using namespace Vc;
27 
28 template<typename Vec> void testZero()
29 {
30  Vec a(Zero), b(Zero);
31  COMPARE(a, b);
32  Vec c, d(1);
33  c.setZero();
34  COMPARE(a, c);
35  d.setZero();
36  COMPARE(a, d);
37  d = static_cast<typename Vec::EntryType>(0);
38  COMPARE(a, d);
39  const typename Vec::EntryType zero = 0;
40  COMPARE(a, Vec(zero));
41  COMPARE(b, Vec(zero));
42  COMPARE(c, Vec(zero));
43  COMPARE(d, Vec(zero));
44 }
45 
46 template<typename Vec> void testCmp()
47 {
48  typedef typename Vec::EntryType T;
49  Vec a(Zero), b(Zero);
50  COMPARE(a, b);
51  if (!(a != b).isEmpty()) {
52  std::cerr << a << " != " << b << ", (a != b) = " << (a != b) << ", (a == b) = " << (a == b) << std::endl;
53  }
54  VERIFY((a != b).isEmpty());
55 
56  Vec c(1);
57  VERIFY((a < c).isFull());
58  VERIFY((c > a).isFull());
59  VERIFY((a <= b).isFull());
60  VERIFY((a <= c).isFull());
61  VERIFY((b >= a).isFull());
62  VERIFY((c >= a).isFull());
63 
64  {
65  const T max = static_cast<T>(std::numeric_limits<T>::max() * 0.95);
66  const T min = 0;
67  const T step = max / 200;
68  T j = min;
69  VERIFY(Vec(Zero) == Vec(j));
70  VERIFY(!(Vec(Zero) < Vec(j)));
71  VERIFY(!(Vec(Zero) > Vec(j)));
72  VERIFY(!(Vec(Zero) != Vec(j)));
73  j += step;
74  for (int i = 0; i < 200; ++i, j += step) {
75  if(Vec(Zero) >= Vec(j)) {
76  std::cout << j << " " << Vec(j) << " " << (Vec(Zero) >= Vec(j)) << std::endl;
77  }
78  VERIFY(Vec(Zero) < Vec(j));
79  VERIFY(Vec(j) > Vec(Zero));
80  VERIFY(!(Vec(Zero) >= Vec(j)));
81  VERIFY(!(Vec(j) <= Vec(Zero)));
82  VERIFY(!static_cast<bool>(Vec(Zero) >= Vec(j)));
83  VERIFY(!static_cast<bool>(Vec(j) <= Vec(Zero)));
84  }
85  }
86  if (std::numeric_limits<T>::min() <= 0) {
87  const T min = static_cast<T>(std::numeric_limits<T>::min() * 0.95);
88  if (min == 0) {
89  return;
90  }
91  const T step = min / T(-201);
92  T j = min;
93  for (int i = 0; i < 200; ++i, j += step) {
94  VERIFY(Vec(j) < Vec(Zero));
95  VERIFY(Vec(Zero) > Vec(j));
96  VERIFY(!(Vec(Zero) <= Vec(j)));
97  VERIFY(!(Vec(j) >= Vec(Zero)));
98  }
99  }
100 }
101 
102 template<typename Vec> void testIsMix()
103 {
104  Vec a(IndexesFromZero);
105  Vec b(Zero);
106  Vec c(One);
107  if (Vec::Size > 1) {
108  VERIFY((a == b).isMix());
109  VERIFY((a != b).isMix());
110  VERIFY((a == c).isMix());
111  VERIFY((a != c).isMix());
112  VERIFY(!(a == a).isMix());
113  VERIFY(!(a != a).isMix());
114  } else { // masks of size 1 can never be a mix of 0 and 1
115  VERIFY(!(a == b).isMix());
116  VERIFY(!(a != b).isMix());
117  VERIFY(!(a == c).isMix());
118  VERIFY(!(a != c).isMix());
119  VERIFY(!(a == a).isMix());
120  VERIFY(!(a != a).isMix());
121  }
122 }
123 
124 template<typename Vec> void testAdd()
125 {
126  Vec a(Zero), b(Zero);
127  COMPARE(a, b);
128 
129  a += 1;
130  Vec c(1);
131  COMPARE(a, c);
132 
133  COMPARE(a, b + 1);
134  COMPARE(a, b + c);
135  Vec x(Zero);
136 }
137 
138 template<typename Vec> void testSub()
139 {
140  Vec a(2), b(2);
141  COMPARE(a, b);
142 
143  a -= 1;
144  Vec c(1);
145  COMPARE(a, c);
146 
147  COMPARE(a, b - 1);
148  COMPARE(a, b - c);
149 }
150 
151 template<typename V> void testMul()
152 {
153  for (int i = 0; i < 10000; ++i) {
154  V a = V::Random();
155  V b = V::Random();
156  V reference = a;
157  for (int j = 0; j < V::Size; ++j) {
158  // this could overflow - but at least the compiler can't know about it so it doesn't
159  // matter that it's undefined behavior in C++. The only thing that matters is what the
160  // hardware does...
161  reference[j] *= b[j];
162  }
163  COMPARE(a * b, reference) << a << " * " << b;
164  }
165 }
166 
167 template<typename Vec> void testMulAdd()
168 {
169  for (unsigned int i = 0; i < 0xffff; ++i) {
170  const Vec i2(i * i + 1);
171  Vec a(i);
172 
173  FUZZY_COMPARE(a * a + 1, i2);
174  }
175 }
176 
177 template<typename Vec> void testMulSub()
178 {
179  typedef typename Vec::EntryType T;
180  for (unsigned int i = 0; i < 0xffff; ++i) {
181  const T j = static_cast<T>(i);
182  const Vec test(j);
183 
184  FUZZY_COMPARE(test * test - test, Vec(j * j - j));
185  }
186 }
187 
188 template<typename Vec> void testDiv()
189 {
190  typedef typename Vec::EntryType T;
191  // If this test fails for ICC see here:
192  // http://software.intel.com/en-us/forums/topic/488995
193 
194  const T stepsize = std::max(T(1), T(std::numeric_limits<T>::max() / 1024));
195  for (T divisor = 1; divisor < 5; ++divisor) {
196  for (T scalar = std::numeric_limits<T>::min(); scalar < std::numeric_limits<T>::max() - stepsize + 1; scalar += stepsize) {
197  Vec vector(scalar);
198  Vec reference(scalar / divisor);
199 
200  COMPARE(vector / divisor, reference) << '\n' << vector << " / " << divisor
201  << ", reference: " << scalar << " / " << divisor << " = " << scalar / divisor;
202  vector /= divisor;
203  COMPARE(vector, reference);
204  }
205  }
206 }
207 
208 template<typename Vec> void testAnd()
209 {
210  Vec a(0x7fff);
211  Vec b(0xf);
212  COMPARE((a & 0xf), b);
213  Vec c(IndexesFromZero);
214  COMPARE(c, (c & 0xf));
215  const typename Vec::EntryType zero = 0;
216  COMPARE((c & 0x7ff0), Vec(zero));
217 }
218 
219 template<typename Vec> void testShift()
220 {
221  typedef typename Vec::EntryType T;
222  const T step = std::max<T>(1, std::numeric_limits<T>::max() / 1000);
223  enum {
224  NShifts = sizeof(T) * 8
225  };
228  x += step) {
229  for (size_t shift = 0; shift < NShifts; ++shift) {
230  const Vec rightShift = x >> shift;
231  const Vec leftShift = x << shift;
232  for (size_t k = 0; k < Vec::Size; ++k) {
233  COMPARE(rightShift[k], T(x[k] >> shift)) << ", x[k] = " << x[k] << ", shift = " << shift;
234  COMPARE(leftShift [k], T(x[k] << shift)) << ", x[k] = " << x[k] << ", shift = " << shift;
235  }
236  }
237  }
238 
239  Vec a(1);
240  Vec b(2);
241 
242  // left shifts
243  COMPARE((a << 1), b);
244  COMPARE((a << 2), (a << 2));
245  COMPARE((a << 2), (b << 1));
246 
247  Vec shifts(IndexesFromZero);
248  a <<= shifts;
249  for (typename Vec::EntryType i = 0, x = 1; i < Vec::Size; ++i, x <<= 1) {
250  COMPARE(a[i], x);
251  }
252 
253  // right shifts
254  a = Vec(4);
255  COMPARE((a >> 1), b);
256  COMPARE((a >> 2), (a >> 2));
257  COMPARE((a >> 2), (b >> 1));
258 
259  a = Vec(16);
260  a >>= shifts;
261  for (typename Vec::EntryType i = 0, x = 16; i < Vec::Size; ++i, x >>= 1) {
262  COMPARE(a[i], x);
263  }
264 }
265 
266 template<typename Vec> void testOnesComplement()
267 {
268  Vec a(One);
269  Vec b = ~a;
270  COMPARE(~a, b);
271  COMPARE(~b, a);
272  COMPARE(~(a + b), Vec(Zero));
273 }
274 
275 template<typename T> struct NegateRangeHelper
276 {
277  typedef int Iterator;
278  static const Iterator Start;
279  static const Iterator End;
280 };
281 template<> struct NegateRangeHelper<unsigned int> {
282  typedef unsigned int Iterator;
283  static const Iterator Start;
284  static const Iterator End;
285 };
286 template<> const int NegateRangeHelper<float>::Start = -0xffffff;
287 template<> const int NegateRangeHelper<float>::End = 0xffffff - 133;
288 template<> const int NegateRangeHelper<double>::Start = -0xffffff;
289 template<> const int NegateRangeHelper<double>::End = 0xffffff - 133;
290 template<> const int NegateRangeHelper<int>::Start = -0x7fffffff;
291 template<> const int NegateRangeHelper<int>::End = 0x7fffffff - 0xee;
292 const unsigned int NegateRangeHelper<unsigned int>::Start = 0;
293 const unsigned int NegateRangeHelper<unsigned int>::End = 0xffffffff - 0xee;
294 template<> const int NegateRangeHelper<short>::Start = -0x7fff;
295 template<> const int NegateRangeHelper<short>::End = 0x7fff - 0xee;
296 template<> const int NegateRangeHelper<unsigned short>::Start = 0;
297 template<> const int NegateRangeHelper<unsigned short>::End = 0xffff - 0xee;
298 
299 template<typename Vec> void testNegate()
300 {
301  typedef typename Vec::EntryType T;
302  typedef NegateRangeHelper<T> Range;
303  for (typename Range::Iterator i = Range::Start; i < Range::End; i += 0xef) {
304  T i2 = static_cast<T>(i);
305  Vec a(i2);
306 
307  COMPARE(static_cast<Vec>(-a), Vec(-i2)) << " i2: " << i2;
308  }
309 }
310 
311 template<typename Vec> void testMin()
312 {
313  typedef typename Vec::EntryType T;
314  typedef typename Vec::Mask Mask;
315  typedef typename Vec::IndexType I;
316 
317  Vec v(I::IndexesFromZero());
318 
319  COMPARE(v.min(), static_cast<T>(0));
320  COMPARE((T(Vec::Size) - v).min(), static_cast<T>(1));
321 
322  int j = 0;
323  Mask m;
324  do {
325  m = allMasks<Vec>(j++);
326  if (m.isEmpty()) {
327  break;
328  }
329  COMPARE(v.min(m), static_cast<T>(m.firstOne())) << m << v;
330  } while (true);
331 }
332 
333 template<typename Vec> void testMax()
334 {
335  typedef typename Vec::EntryType T;
336  typedef typename Vec::Mask Mask;
337  typedef typename Vec::IndexType I;
338 
339  Vec v(I::IndexesFromZero());
340 
341  COMPARE(v.max(), static_cast<T>(Vec::Size - 1));
342  v = T(Vec::Size) - v;
343  COMPARE(v.max(), static_cast<T>(Vec::Size));
344 
345  int j = 0;
346  Mask m;
347  do {
348  m = allMasks<Vec>(j++);
349  if (m.isEmpty()) {
350  break;
351  }
352  COMPARE(v.max(m), static_cast<T>(Vec::Size - m.firstOne())) << m << v;
353  } while (true);
354 }
355 
356 template<typename Vec> void testProduct()
357 {
358  typedef typename Vec::EntryType T;
359  typedef typename Vec::Mask Mask;
360 
361  for (int i = 0; i < 10; ++i) {
362  T x = static_cast<T>(i);
363  Vec v(x);
364  T x2 = x;
365  for (int k = Vec::Size; k > 1; k /= 2) {
366  x2 *= x2;
367  }
368  COMPARE(v.product(), x2);
369 
370  int j = 0;
371  Mask m;
372  do {
373  m = allMasks<Vec>(j++);
374  if (m.isEmpty()) {
375  break;
376  }
377  if (std::numeric_limits<T>::is_exact) {
378  x2 = x;
379  for (int k = m.count(); k > 1; --k) {
380  x2 *= x;
381  }
382  } else {
383  x2 = static_cast<T>(pow(static_cast<double>(x), m.count()));
384  }
385  COMPARE(v.product(m), x2) << m << v;
386  } while (true);
387  }
388 }
389 
390 template<typename Vec> void testSum()
391 {
392  typedef typename Vec::EntryType T;
393  typedef typename Vec::Mask Mask;
394 
395  for (int i = 0; i < 10; ++i) {
396  T x = static_cast<T>(i);
397  Vec v(x);
398  COMPARE(v.sum(), x * Vec::Size);
399 
400  int j = 0;
401  Mask m;
402  do {
403  m = allMasks<Vec>(j++);
404  COMPARE(v.sum(m), x * m.count()) << m << v;
405  } while (!m.isEmpty());
406  }
407 }
408 
409 template<typename V> void fma()
410 {
411  for (int i = 0; i < 1000; ++i) {
412  V a = V::Random();
413  const V b = V::Random();
414  const V c = V::Random();
415  const V reference = a * b + c;
416  a.fusedMultiplyAdd(b, c);
417  COMPARE(a, reference) << ", a = " << a << ", b = " << b << ", c = " << c;
418  }
419 }
420 
421 template<> void fma<float_v>()
422 {
423  float_v b = Vc_buildFloat(1, 0x000001, 0);
424  float_v c = Vc_buildFloat(1, 0x000000, -24);
425  float_v a = b;
426  /*a *= b;
427  a += c;
428  COMPARE(a, float_v(Vc_buildFloat(1, 0x000002, 0)));
429  a = b;*/
430  a.fusedMultiplyAdd(b, c);
431  COMPARE(a, float_v(Vc_buildFloat(1, 0x000003, 0)));
432 
433  a = Vc_buildFloat(1, 0x000002, 0);
434  b = Vc_buildFloat(1, 0x000002, 0);
435  c = Vc_buildFloat(-1, 0x000000, 0);
436  /*a *= b;
437  a += c;
438  COMPARE(a, float_v(Vc_buildFloat(1, 0x000000, -21)));
439  a = b;*/
440  a.fusedMultiplyAdd(b, c); // 1 + 2^-21 + 2^-44 - 1 == (1 + 2^-20)*2^-18
441  COMPARE(a, float_v(Vc_buildFloat(1, 0x000001, -21)));
442 }
443 
444 template<> void fma<sfloat_v>()
445 {
446  sfloat_v b = Vc_buildFloat(1, 0x000001, 0);
447  sfloat_v c = Vc_buildFloat(1, 0x000000, -24);
448  sfloat_v a = b;
449  /*a *= b;
450  a += c;
451  COMPARE(a, sfloat_v(Vc_buildFloat(1, 0x000002, 0)));
452  a = b;*/
453  a.fusedMultiplyAdd(b, c);
454  COMPARE(a, sfloat_v(Vc_buildFloat(1, 0x000003, 0)));
455 
456  a = Vc_buildFloat(1, 0x000002, 0);
457  b = Vc_buildFloat(1, 0x000002, 0);
458  c = Vc_buildFloat(-1, 0x000000, 0);
459  /*a *= b;
460  a += c;
461  COMPARE(a, sfloat_v(Vc_buildFloat(1, 0x000000, -21)));
462  a = b;*/
463  a.fusedMultiplyAdd(b, c); // 1 + 2^-21 + 2^-44 - 1 == (1 + 2^-20)*2^-18
464  COMPARE(a, sfloat_v(Vc_buildFloat(1, 0x000001, -21)));
465 }
466 
467 template<> void fma<double_v>()
468 {
469  double_v b = Vc_buildDouble(1, 0x0000000000001, 0);
470  double_v c = Vc_buildDouble(1, 0x0000000000000, -53);
471  double_v a = b;
472  a.fusedMultiplyAdd(b, c);
473  COMPARE(a, double_v(Vc_buildDouble(1, 0x0000000000003, 0)));
474 
475  a = Vc_buildDouble(1, 0x0000000000002, 0);
476  b = Vc_buildDouble(1, 0x0000000000002, 0);
477  c = Vc_buildDouble(-1, 0x0000000000000, 0);
478  a.fusedMultiplyAdd(b, c); // 1 + 2^-50 + 2^-102 - 1
479  COMPARE(a, double_v(Vc_buildDouble(1, 0x0000000000001, -50)));
480 }
481 
482 int main(int argc, char **argv)
483 {
484  initTest(argc, argv);
485 
486  testAllTypes(fma);
487 
488  runTest(testZero<int_v>);
489  runTest(testZero<uint_v>);
490  runTest(testZero<float_v>);
491  runTest(testZero<double_v>);
492  runTest(testZero<short_v>);
493  runTest(testZero<ushort_v>);
494  runTest(testZero<sfloat_v>);
495 
496  runTest(testCmp<int_v>);
497  runTest(testCmp<uint_v>);
498  runTest(testCmp<float_v>);
499  runTest(testCmp<double_v>);
500  runTest(testCmp<short_v>);
501  runTest(testCmp<ushort_v>);
502  runTest(testCmp<sfloat_v>);
503 
504  runTest(testIsMix<int_v>);
505  runTest(testIsMix<uint_v>);
506  //runTest(testIsMix<float_v>);
507  //runTest(testIsMix<double_v>);
508  runTest(testIsMix<short_v>);
509  runTest(testIsMix<ushort_v>);
510  //runTest(testIsMix<sfloat_v>);
511 
512  runTest(testAdd<int_v>);
513  runTest(testAdd<uint_v>);
514  runTest(testAdd<float_v>);
515  runTest(testAdd<double_v>);
516  runTest(testAdd<short_v>);
517  runTest(testAdd<ushort_v>);
518  runTest(testAdd<sfloat_v>);
519 
520  runTest(testSub<int_v>);
521  runTest(testSub<uint_v>);
522  runTest(testSub<float_v>);
523  runTest(testSub<double_v>);
524  runTest(testSub<short_v>);
525  runTest(testSub<ushort_v>);
526  runTest(testSub<sfloat_v>);
527 
528  runTest(testMul<int_v>);
529  runTest(testMul<uint_v>);
530  runTest(testMul<float_v>);
531  runTest(testMul<double_v>);
532  runTest(testMul<short_v>);
533  runTest(testMul<ushort_v>);
534  runTest(testMul<sfloat_v>);
535 
536  runTest(testDiv<int_v>);
537  runTest(testDiv<uint_v>);
538  runTest(testDiv<float_v>);
539  runTest(testDiv<double_v>);
540  runTest(testDiv<short_v>);
541  runTest(testDiv<ushort_v>);
542  runTest(testDiv<sfloat_v>);
543 
544  runTest(testAnd<int_v>);
545  runTest(testAnd<uint_v>);
546  runTest(testAnd<short_v>);
547  runTest(testAnd<ushort_v>);
548  // no operator& for float/double
549 
550  runTest(testShift<int_v>);
551  runTest(testShift<uint_v>);
552  runTest(testShift<short_v>);
553  runTest(testShift<ushort_v>);
554 
555  runTest(testMulAdd<int_v>);
556  runTest(testMulAdd<uint_v>);
557  runTest(testMulAdd<float_v>);
558  runTest(testMulAdd<double_v>);
559  runTest(testMulAdd<short_v>);
560  runTest(testMulAdd<ushort_v>);
561  runTest(testMulAdd<sfloat_v>);
562 
563  runTest(testMulSub<int_v>);
564  runTest(testMulSub<uint_v>);
565  runTest(testMulSub<float_v>);
566  runTest(testMulSub<double_v>);
567  runTest(testMulSub<short_v>);
568  runTest(testMulSub<ushort_v>);
569  runTest(testMulSub<sfloat_v>);
570 
571  runTest(testOnesComplement<int_v>);
572  runTest(testOnesComplement<uint_v>);
573  runTest(testOnesComplement<short_v>);
574  runTest(testOnesComplement<ushort_v>);
575 
581 
582  return 0;
583 }
Vector< sfloat > sfloat_v
Definition: vector.h:418
VECTOR_NAMESPACE::sfloat_v sfloat_v
Definition: vector.h:82
static Vc_ALWAYS_INLINE int_v min(const int_v &x, const int_v &y)
Definition: vector.h:433
void testMulSub()
#define FUZZY_COMPARE(a, b)
Definition: unittest.h:506
void initTest(int argc, char **argv)
Definition: unittest.h:169
int main(int argc, char **argv)
const char * Size
Definition: TXMLSetup.cxx:56
double T(double x)
Definition: ChebyshevPol.h:34
void fma< sfloat_v >()
TArc * a
Definition: textangle.C:12
void fma< double_v >()
void testOnesComplement()
void testMulAdd()
void fma< float_v >()
static const double x2[5]
Double_t x[n]
Definition: legend1.C:17
#define COMPARE(a, b)
Definition: unittest.h:509
double pow(double, double)
#define testAllTypes(name)
Definition: unittest.h:43
void testMul()
#define Vc_buildDouble(sign, mantissa, exponent)
Definition: macros.h:283
Vector< double > double_v
Definition: vector.h:416
SVector< double, 2 > v
Definition: Dict.h:5
void testSum()
VECTOR_NAMESPACE::double_v double_v
Definition: vector.h:80
void testAdd()
TMarker * m
Definition: textangle.C:8
void testDiv()
void testZero()
Definition: arithmetics.cpp:28
void testIsMix()
#define VERIFY(cond)
Definition: unittest.h:515
#define Vc_buildFloat(sign, mantissa, exponent)
Definition: macros.h:294
void Random()
Definition: utils.cpp:154
void testSub()
VECTOR_NAMESPACE::float_v float_v
Definition: vector.h:84
static Vc_ALWAYS_INLINE int_v max(const int_v &x, const int_v &y)
Definition: vector.h:440
Ta Range(0, 0, 1, 1)
void End()
Definition: casts.h:28
void testMax()
#define I(x, y, z)
void testShift()
void testMin()
void testProduct()
void testNegate()
void testCmp()
Definition: arithmetics.cpp:46
void testAnd()
void fma()
#define runTest(name)
Definition: unittest.h:42
Vector< float > float_v
Definition: vector.h:417