• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////
2 //  Copyright 2011-9 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt
5 
6 #define BOOST_CHRONO_HEADER_ONLY
7 
8 #ifdef _MSC_VER
9 #define _SCL_SECURE_NO_WARNINGS
10 #endif
11 
12 #if !defined(TEST_MPF) && !defined(TEST_MPZ) && \
13     !defined(TEST_CPP_DEC_FLOAT) && !defined(TEST_MPFR) && !defined(TEST_MPQ) && !defined(TEST_TOMMATH) && \
14     !defined(TEST_TOMMATH_BOOST_RATIONAL) && !defined(TEST_MPZ_BOOST_RATIONAL) && !defined(TEST_CPP_INT) && \
15     !defined(TEST_CPP_INT_RATIONAL) && !defined(TEST_CPP_BIN_FLOAT)
16 #define TEST_MPF
17 #define TEST_MPZ
18 #define TEST_MPQ
19 #define TEST_MPFR
20 #define TEST_CPP_DEC_FLOAT
21 #define TEST_MPQ
22 #define TEST_TOMMATH
23 #define TEST_CPP_INT
24 #define TEST_CPP_INT_RATIONAL
25 #define TEST_CPP_BIN_FLOAT
26 
27 #ifdef _MSC_VER
28 #pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
29 #endif
30 #ifdef __GNUC__
31 #pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!"
32 #endif
33 
34 #endif
35 
36 #include <boost/chrono.hpp>
37 #include <vector>
38 #include <map>
39 #include <string>
40 #include <cstring>
41 #include <cctype>
42 #include <iostream>
43 #include <iomanip>
44 #include <boost/random/mersenne_twister.hpp>
45 #include <boost/random/uniform_int.hpp>
46 #include <boost/multiprecision/number.hpp>
47 
48 template <class Clock>
49 struct stopwatch
50 {
51    typedef typename Clock::duration duration;
stopwatchstopwatch52    stopwatch()
53    {
54       m_start = Clock::now();
55    }
elapsedstopwatch56    duration elapsed()
57    {
58       return Clock::now() - m_start;
59    }
resetstopwatch60    void reset()
61    {
62       m_start = Clock::now();
63    }
64 
65  private:
66    typename Clock::time_point m_start;
67 };
68 
69 extern unsigned bits_wanted; // for integer types
70 
71 template <class T, int Type>
72 struct tester
73 {
testertester74    tester()
75    {
76       a.assign(500, 0);
77       for (int i = 0; i < 500; ++i)
78       {
79          b.push_back(generate_random());
80          c.push_back(generate_random());
81          small.push_back(gen());
82       }
83    }
test_addtester84    double test_add()
85    {
86       stopwatch<boost::chrono::high_resolution_clock> w;
87       for (unsigned i = 0; i < 1000; ++i)
88       {
89          for (unsigned j = 0; j < b.size(); ++j)
90             a[j] = b[j] + c[j];
91       }
92       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
93    }
test_subtracttester94    double test_subtract()
95    {
96       stopwatch<boost::chrono::high_resolution_clock> w;
97       for (unsigned i = 0; i < 1000; ++i)
98       {
99          for (unsigned j = 0; j < b.size(); ++j)
100             a[j] = b[j] - c[j];
101       }
102       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
103    }
test_add_inttester104    double test_add_int()
105    {
106       stopwatch<boost::chrono::high_resolution_clock> w;
107       for (unsigned i = 0; i < 1000; ++i)
108       {
109          for (unsigned j = 0; j < b.size(); ++j)
110             a[j] = b[j] + 1;
111       }
112       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
113    }
test_subtract_inttester114    double test_subtract_int()
115    {
116       stopwatch<boost::chrono::high_resolution_clock> w;
117       for (unsigned i = 0; i < 1000; ++i)
118       {
119          for (unsigned j = 0; j < b.size(); ++j)
120             a[j] = b[j] - 1;
121       }
122       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
123    }
test_multiplytester124    double test_multiply()
125    {
126       stopwatch<boost::chrono::high_resolution_clock> w;
127       for (unsigned i = 0; i < 1000; ++i)
128       {
129          for (unsigned k = 0; k < b.size(); ++k)
130             a[k] = b[k] * c[k];
131       }
132       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
133    }
test_multiply_inttester134    double test_multiply_int()
135    {
136       stopwatch<boost::chrono::high_resolution_clock> w;
137       for (unsigned i = 0; i < 1000; ++i)
138       {
139          for (unsigned j = 0; j < b.size(); ++j)
140             a[j] = b[j] * 3;
141       }
142       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
143    }
test_dividetester144    double test_divide()
145    {
146       stopwatch<boost::chrono::high_resolution_clock> w;
147       for (unsigned i = 0; i < 1000; ++i)
148       {
149          for (unsigned j = 0; j < b.size(); ++j)
150             a[j] = b[j] / c[j] + b[j] / small[j];
151       }
152       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
153    }
test_divide_inttester154    double test_divide_int()
155    {
156       stopwatch<boost::chrono::high_resolution_clock> w;
157       for (unsigned i = 0; i < 1000; ++i)
158       {
159          for (unsigned j = 0; j < b.size(); ++j)
160             a[j] = b[j] / 3;
161       }
162       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
163    }
test_strtester164    double test_str(const boost::mpl::false_&)
165    {
166       stopwatch<boost::chrono::high_resolution_clock> w;
167       for (unsigned i = 0; i < b.size(); ++i)
168          a[i] = boost::lexical_cast<T>(boost::lexical_cast<std::string>(b[i]));
169       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
170    }
test_strtester171    double test_str(const boost::mpl::true_&)
172    {
173       stopwatch<boost::chrono::high_resolution_clock> w;
174       for (unsigned i = 0; i < b.size(); ++i)
175          a[i].assign(b[i].str());
176       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
177    }
test_strtester178    double test_str()
179    {
180       return test_str(boost::is_class<T>());
181    }
182    //
183    // The following tests only work for integer types:
184    //
test_modtester185    double test_mod()
186    {
187       stopwatch<boost::chrono::high_resolution_clock> w;
188       for (unsigned i = 0; i < 1000; ++i)
189       {
190          for (unsigned i = 0; i < b.size(); ++i)
191             a[i] = b[i] % c[i] + b[i] % small[i];
192       }
193       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
194    }
test_mod_inttester195    double test_mod_int()
196    {
197       stopwatch<boost::chrono::high_resolution_clock> w;
198       for (unsigned i = 0; i < 1000; ++i)
199       {
200          for (unsigned i = 0; i < b.size(); ++i)
201             a[i] = b[i] % 254;
202       }
203       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
204    }
test_ortester205    double test_or()
206    {
207       stopwatch<boost::chrono::high_resolution_clock> w;
208       for (unsigned i = 0; i < 1000; ++i)
209       {
210          for (unsigned i = 0; i < b.size(); ++i)
211             a[i] = b[i] | c[i];
212       }
213       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
214    }
test_or_inttester215    double test_or_int()
216    {
217       stopwatch<boost::chrono::high_resolution_clock> w;
218       for (unsigned i = 0; i < 1000; ++i)
219       {
220          for (unsigned i = 0; i < b.size(); ++i)
221             a[i] = b[i] | 234;
222       }
223       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
224    }
test_andtester225    double test_and()
226    {
227       stopwatch<boost::chrono::high_resolution_clock> w;
228       for (unsigned i = 0; i < 1000; ++i)
229       {
230          for (unsigned i = 0; i < b.size(); ++i)
231             a[i] = b[i] & c[i];
232       }
233       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
234    }
test_and_inttester235    double test_and_int()
236    {
237       stopwatch<boost::chrono::high_resolution_clock> w;
238       for (unsigned i = 0; i < 1000; ++i)
239       {
240          for (unsigned i = 0; i < b.size(); ++i)
241             a[i] = b[i] & 234;
242       }
243       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
244    }
test_xortester245    double test_xor()
246    {
247       stopwatch<boost::chrono::high_resolution_clock> w;
248       for (unsigned i = 0; i < 1000; ++i)
249       {
250          for (unsigned i = 0; i < b.size(); ++i)
251             a[i] = b[i] ^ c[i];
252       }
253       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
254    }
test_xor_inttester255    double test_xor_int()
256    {
257       stopwatch<boost::chrono::high_resolution_clock> w;
258       for (unsigned i = 0; i < 1000; ++i)
259       {
260          for (unsigned i = 0; i < b.size(); ++i)
261             a[i] = b[i] ^ 234;
262       }
263       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
264    }
test_complementtester265    double test_complement()
266    {
267       stopwatch<boost::chrono::high_resolution_clock> w;
268       for (unsigned i = 0; i < 1000; ++i)
269       {
270          for (unsigned i = 0; i < b.size(); ++i)
271             a[i] = ~b[i];
272       }
273       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
274    }
test_left_shifttester275    double test_left_shift()
276    {
277       int                                             max_shift = std::numeric_limits<T>::is_bounded ? std::numeric_limits<T>::digits : bits_wanted;
278       int                                             shift     = 0;
279       stopwatch<boost::chrono::high_resolution_clock> w;
280       for (unsigned i = 0; i < 1000; ++i)
281       {
282          for (unsigned i = 0; i < b.size(); ++i)
283             a[i] = b[i] << (shift++ % max_shift);
284       }
285       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
286    }
test_right_shifttester287    double test_right_shift()
288    {
289       int                                             max_shift = 2 + std::numeric_limits<T>::is_bounded ? std::numeric_limits<T>::digits : bits_wanted;
290       int                                             shift     = 0;
291       stopwatch<boost::chrono::high_resolution_clock> w;
292       for (unsigned i = 0; i < 1000; ++i)
293       {
294          for (unsigned i = 0; i < b.size(); ++i)
295             a[i] = b[i] >> (shift++) % max_shift;
296       }
297       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
298    }
test_gcdtester299    double test_gcd()
300    {
301       using boost::integer::gcd;
302       stopwatch<boost::chrono::high_resolution_clock> w;
303       for (unsigned i = 0; i < 1000; ++i)
304       {
305          for (unsigned i = 0; i < b.size(); ++i)
306             a[i] = gcd(b[i], c[i]);
307       }
308       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
309    }
test_powmtester310    double test_powm()
311    {
312       stopwatch<boost::chrono::high_resolution_clock> w;
313       for (unsigned i = 0; i < 25; ++i)
314       {
315          for (unsigned i = 0; i < b.size(); ++i)
316             a[i] = powm(b[i], b[i] / 2, c[i]);
317       }
318       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
319    }
test_constructtester320    double test_construct()
321    {
322       std::allocator<T>                               alloc;
323       T*                                              pt = alloc.allocate(1000);
324       stopwatch<boost::chrono::high_resolution_clock> w;
325       for (unsigned i = 0; i < 1000; ++i)
326       {
327          for (unsigned j = 0; j < 1000; ++j)
328             new (pt + j) T();
329          for (unsigned j = 0; j < 1000; ++j)
330             std::allocator_traits<std::allocator<T> >::destroy(alloc, pt + j);
331       }
332       double result = boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
333       alloc.deallocate(pt, 1000);
334       return result;
335    }
test_construct_unsignedtester336    double test_construct_unsigned()
337    {
338       std::allocator<T>                               alloc;
339       T*                                              pt = alloc.allocate(1000);
340       stopwatch<boost::chrono::high_resolution_clock> w;
341       for (unsigned i = 0; i < 1000; ++i)
342       {
343          for (unsigned j = 0; j < 1000; ++j)
344             new (pt + j) T(j);
345          for (unsigned j = 0; j < 1000; ++j)
346             std::allocator_traits<std::allocator<T> >::destroy(alloc, pt + j);
347       }
348       double result = boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
349       alloc.deallocate(pt, 1000);
350       return result;
351    }
test_construct_unsigned_lltester352    double test_construct_unsigned_ll()
353    {
354       std::allocator<T>                               alloc;
355       T*                                              pt = alloc.allocate(1000);
356       stopwatch<boost::chrono::high_resolution_clock> w;
357       for (unsigned i = 0; i < 1000; ++i)
358       {
359          for (unsigned long long j = 0; j < 1000; ++j)
360             new (pt + j) T(j);
361          for (unsigned j = 0; j < 1000; ++j)
362             std::allocator_traits<std::allocator<T>  >::destroy(alloc, pt + j);
363       }
364       double result = boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
365       alloc.deallocate(pt, 1000);
366       return result;
367    }
368 
369    //
370    // Hetero operations:
371    //
372    template <class U>
get_hetero_test_valuetester373    static U get_hetero_test_value(boost::mpl::false_ const&)
374    {
375       return U(2) / 3;
376    }
377    template <class U>
get_hetero_test_valuetester378    static U get_hetero_test_value(boost::mpl::true_ const&)
379    {
380       return (std::numeric_limits<U>::max)() >> 4;
381    }
382    template <class U>
get_hetero_test_valuetester383    static U get_hetero_test_value()
384    {
385       return get_hetero_test_value<U>(boost::is_integral<U>());
386    }
387    template <class U>
test_multiply_heterotester388    double test_multiply_hetero()
389    {
390       static const U                                  val = get_hetero_test_value<U>();
391       stopwatch<boost::chrono::high_resolution_clock> w;
392       for (unsigned i = 0; i < 1000; ++i)
393       {
394          for (unsigned j = 0; j < b.size(); ++j)
395             a[j] = b[j] * val;
396       }
397       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
398    }
399    template <class U>
test_inplace_multiply_heterotester400    double test_inplace_multiply_hetero()
401    {
402       static const U val = get_hetero_test_value<U>();
403       stopwatch<boost::chrono::high_resolution_clock> w;
404       for (unsigned i = 0; i < 1000; ++i)
405       {
406          for (unsigned j = 0; j < b.size(); ++j)
407             a[j] = b[j], a[j] *= val;
408       }
409       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
410    }
411    template <class U>
test_add_heterotester412    double test_add_hetero()
413    {
414       static const U                                  val = get_hetero_test_value<U>();
415       stopwatch<boost::chrono::high_resolution_clock> w;
416       for (unsigned i = 0; i < 1000; ++i)
417       {
418          for (unsigned j = 0; j < b.size(); ++j)
419             a[j] = b[j] + val;
420       }
421       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
422    }
423    template <class U>
test_inplace_add_heterotester424    double test_inplace_add_hetero()
425    {
426       static const U val = get_hetero_test_value<U>();
427       stopwatch<boost::chrono::high_resolution_clock> w;
428       for (unsigned i = 0; i < 1000; ++i)
429       {
430          for (unsigned j = 0; j < b.size(); ++j)
431             a[j] = b[j], a[j] += val;
432       }
433       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
434    }
435    template <class U>
test_subtract_heterotester436    double test_subtract_hetero()
437    {
438       static const U                                  val = get_hetero_test_value<U>();
439       stopwatch<boost::chrono::high_resolution_clock> w;
440       for (unsigned i = 0; i < 1000; ++i)
441       {
442          for (unsigned j = 0; j < b.size(); ++j)
443             a[j] = b[j] - val;
444       }
445       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
446    }
447    template <class U>
test_inplace_subtract_heterotester448    double test_inplace_subtract_hetero()
449    {
450       static const U val = get_hetero_test_value<U>();
451       stopwatch<boost::chrono::high_resolution_clock> w;
452       for (unsigned i = 0; i < 1000; ++i)
453       {
454          for (unsigned j = 0; j < b.size(); ++j)
455             a[j] = b[j], a[j] -= val;
456       }
457       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
458    }
459    template <class U>
test_divide_heterotester460    double test_divide_hetero()
461    {
462       static const U                                  val = get_hetero_test_value<U>();
463       stopwatch<boost::chrono::high_resolution_clock> w;
464       for (unsigned i = 0; i < 1000; ++i)
465       {
466          for (unsigned j = 0; j < b.size(); ++j)
467             a[j] = b[j] / val;
468       }
469       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
470    }
471    template <class U>
test_inplace_divide_heterotester472    double test_inplace_divide_hetero()
473    {
474       static const U val = get_hetero_test_value<U>();
475       stopwatch<boost::chrono::high_resolution_clock> w;
476       for (unsigned i = 0; i < 1000; ++i)
477       {
478          for (unsigned j = 0; j < b.size(); ++j)
479             a[j] = b[j], a[j] /= val;
480       }
481       return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
482    }
483 
484  private:
generate_randomtester485    T generate_random()
486    {
487       return generate_random(boost::mpl::int_<Type>());
488    }
generate_randomtester489    T generate_random(const boost::mpl::int_<boost::multiprecision::number_kind_floating_point>&)
490    {
491       T val      = gen();
492       T prev_val = -1;
493       while (val != prev_val)
494       {
495          val *= (gen.max)();
496          prev_val = val;
497          val += gen();
498       }
499       int e;
500       val = frexp(val, &e);
501 
502       typedef typename T::backend_type::exponent_type        e_type;
503       static boost::random::uniform_int_distribution<e_type> ui(-30, 30);
504       return ldexp(val, static_cast<int>(ui(gen)));
505    }
generate_randomtester506    T generate_random(const boost::mpl::int_<boost::multiprecision::number_kind_integer>&)
507    {
508       typedef boost::random::mt19937::result_type random_type;
509 
510       T        max_val;
511       unsigned digits;
512       if (std::numeric_limits<T>::is_bounded)
513       {
514          max_val = (std::numeric_limits<T>::max)();
515          digits  = std::numeric_limits<T>::digits;
516       }
517       else
518       {
519          max_val = T(1) << bits_wanted;
520          digits  = bits_wanted;
521       }
522 
523       unsigned bits_per_r_val = std::numeric_limits<random_type>::digits - 1;
524       while ((random_type(1) << bits_per_r_val) > (gen.max)())
525          --bits_per_r_val;
526 
527       unsigned terms_needed = digits / bits_per_r_val + 1;
528 
529       T val = 0;
530       for (unsigned i = 0; i < terms_needed; ++i)
531       {
532          val *= (gen.max)();
533          val += gen();
534       }
535       val %= max_val;
536       return val;
537    }
generate_randomtester538    T generate_random(const boost::mpl::int_<boost::multiprecision::number_kind_rational>&)
539    {
540       typedef boost::random::mt19937::result_type                     random_type;
541       typedef typename boost::multiprecision::component_type<T>::type IntType;
542 
543       IntType  max_val;
544       unsigned digits;
545       if (std::numeric_limits<IntType>::is_bounded)
546       {
547          max_val = (std::numeric_limits<IntType>::max)();
548          digits  = std::numeric_limits<IntType>::digits;
549       }
550       else
551       {
552          max_val = IntType(1) << bits_wanted;
553          digits  = bits_wanted;
554       }
555 
556       unsigned bits_per_r_val = std::numeric_limits<random_type>::digits - 1;
557       while ((random_type(1) << bits_per_r_val) > (gen.max)())
558          --bits_per_r_val;
559 
560       unsigned terms_needed = digits / bits_per_r_val + 1;
561 
562       IntType val   = 0;
563       IntType denom = 0;
564       for (unsigned i = 0; i < terms_needed; ++i)
565       {
566          val *= (gen.max)();
567          val += gen();
568       }
569       for (unsigned i = 0; i < terms_needed; ++i)
570       {
571          denom *= (gen.max)();
572          denom += gen();
573       }
574       if (denom == 0)
575          denom = 1;
576       val %= max_val;
577       denom %= max_val;
578       return T(val, denom);
579    }
580    std::vector<T>                a, b, c, small;
581    static boost::random::mt19937 gen;
582 };
583 
584 template <class N, int V>
585 boost::random::mt19937 tester<N, V>::gen;
586 
category_name(const boost::mpl::int_<boost::multiprecision::number_kind_integer> &)587 inline const char* category_name(const boost::mpl::int_<boost::multiprecision::number_kind_integer>&)
588 {
589    return "integer";
590 }
category_name(const boost::mpl::int_<boost::multiprecision::number_kind_floating_point> &)591 inline const char* category_name(const boost::mpl::int_<boost::multiprecision::number_kind_floating_point>&)
592 {
593    return "float";
594 }
category_name(const boost::mpl::int_<boost::multiprecision::number_kind_rational> &)595 inline const char* category_name(const boost::mpl::int_<boost::multiprecision::number_kind_rational>&)
596 {
597    return "rational";
598 }
599 
600 //
601 // Keys in order are:
602 // Category
603 // Operator
604 // Type
605 // Precision
606 // Time
607 //
608 extern std::map<std::string, std::map<std::string, std::map<std::string, std::map<int, double> > > > result_table;
609 
report_result(const char * cat,const char * type,const char * op,unsigned precision,double time)610 inline void report_result(const char* cat, const char* type, const char* op, unsigned precision, double time)
611 {
612    std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(35) << op << time << std::endl;
613    result_table[cat][op][type][precision] = time;
614 }
615 
616 template <class Number, int N>
test_int_ops(tester<Number,N> & t,const char * type,unsigned precision,const boost::mpl::int_<boost::multiprecision::number_kind_integer> &)617 void test_int_ops(tester<Number, N>& t, const char* type, unsigned precision, const boost::mpl::int_<boost::multiprecision::number_kind_integer>&)
618 {
619    const char* cat = "integer";
620    report_result(cat, type, "%", precision, t.test_mod());
621    report_result(cat, type, "|", precision, t.test_or());
622    report_result(cat, type, "&", precision, t.test_and());
623    report_result(cat, type, "^", precision, t.test_xor());
624    //report_result(cat, type, "~", precision, t.test_complement());
625    report_result(cat, type, "<<", precision, t.test_left_shift());
626    report_result(cat, type, ">>", precision, t.test_right_shift());
627    // integer ops:
628    report_result(cat, type, "%(int)", precision, t.test_mod_int());
629    report_result(cat, type, "|(int)", precision, t.test_or_int());
630    report_result(cat, type, "&(int)", precision, t.test_and_int());
631    report_result(cat, type, "^(int)", precision, t.test_xor_int());
632    report_result(cat, type, "gcd", precision, t.test_gcd());
633    if(precision <= 1024)
634       report_result(cat, type, "powm", precision, t.test_powm());
635 }
636 template <class Number, int N, class U>
test_int_ops(tester<Number,N> &,const char *,unsigned,const U &)637 void test_int_ops(tester<Number, N>&, const char*, unsigned, const U&)
638 {
639 }
640 
641 template <class Number>
test(const char * type,unsigned precision)642 void test(const char* type, unsigned precision)
643 {
644    bits_wanted = precision;
645    tester<Number, boost::multiprecision::number_category<Number>::value> t;
646    const char*                                                           cat = category_name(typename boost::multiprecision::number_category<Number>::type());
647    //
648    // call t.test_multiply() first so that the destination operands are
649    // forced to perform whatever memory allocation may be needed.  That way
650    // we measure only algorithm performance, and not memory allocation effects.
651    //
652    t.test_multiply();
653    //
654    // Now the actual tests:
655    //
656 #ifndef TEST_MUL_ONLY
657    report_result(cat, type, "+", precision, t.test_add());
658    report_result(cat, type, "-", precision, t.test_subtract());
659 #endif
660    report_result(cat, type, "*", precision, t.test_multiply());
661 #ifndef TEST_MUL_ONLY
662    report_result(cat, type, "/", precision, t.test_divide());
663    report_result(cat, type, "str", precision, t.test_str());
664    // integer ops:
665    report_result(cat, type, "+(int)", precision, t.test_add_int());
666    report_result(cat, type, "-(int)", precision, t.test_subtract_int());
667    report_result(cat, type, "*(int)", precision, t.test_multiply_int());
668    report_result(cat, type, "/(int)", precision, t.test_divide_int());
669    // construction and destruction:
670    report_result(cat, type, "construct", precision, t.test_construct());
671    report_result(cat, type, "construct(unsigned)", precision, t.test_construct_unsigned());
672    report_result(cat, type, "construct(unsigned long long)", precision, t.test_construct_unsigned_ll());
673    test_int_ops(t, type, precision, typename boost::multiprecision::number_category<Number>::type());
674    // Hetero ops:
675    report_result(cat, type, "+(unsigned long long)", precision, t.template test_add_hetero<unsigned long long>());
676    report_result(cat, type, "-(unsigned long long)", precision, t.template test_subtract_hetero<unsigned long long>());
677    report_result(cat, type, "*(unsigned long long)", precision, t.template test_multiply_hetero<unsigned long long>());
678    report_result(cat, type, "/(unsigned long long)", precision, t.template test_divide_hetero<unsigned long long>());
679    report_result(cat, type, "+=(unsigned long long)", precision, t.template test_inplace_add_hetero<unsigned long long>());
680    report_result(cat, type, "-=(unsigned long long)", precision, t.template test_inplace_subtract_hetero<unsigned long long>());
681    report_result(cat, type, "*=(unsigned long long)", precision, t.template test_inplace_multiply_hetero<unsigned long long>());
682    report_result(cat, type, "/=(unsigned long long)", precision, t.template test_inplace_divide_hetero<unsigned long long>());
683 #endif
684 }
685 
686 void test01();
687 void test02();
688 void test03();
689 void test04();
690 void test05();
691 void test06();
692 void test07();
693 void test08();
694 void test09();
695 void test10();
696 void test11();
697 void test12();
698 void test13();
699 void test14();
700 void test15();
701 void test16();
702 void test17();
703 void test18();
704 void test19();
705 void test20();
706 void test21();
707 void test22();
708 void test23();
709 void test24();
710 void test25();
711 void test26();
712 void test27();
713 void test28();
714 void test29();
715 void test30();
716 void test31();
717 void test32();
718 void test33();
719 void test34();
720 void test35();
721 void test36();
722 void test37();
723 void test38();
724 void test39();
725 void test40();
726 void test41();
727 void test42();
728 void test43();
729 void test44();
730 void test45();
731 void test46();
732 void test47();
733 void test48();
734 void test49();
735 void test50();
736 void test51();
737 
738