]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/multiprecision/performance/performance_test.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / multiprecision / performance / performance_test.cpp
1 ///////////////////////////////////////////////////////////////
2 // Copyright 2011 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) && !defined(TEST_TOMMATH_BOOST_RATIONAL) && !defined(TEST_MPZ_BOOST_RATIONAL) && !defined(TEST_CPP_INT) && !defined(TEST_CPP_INT_RATIONAL) && !defined(TEST_CPP_BIN_FLOAT)
14 #define TEST_MPF
15 #define TEST_MPZ
16 #define TEST_MPQ
17 #define TEST_MPFR
18 #define TEST_CPP_DEC_FLOAT
19 #define TEST_MPQ
20 #define TEST_TOMMATH
21 #define TEST_CPP_INT
22 #define TEST_CPP_INT_RATIONAL
23 #define TEST_CPP_BIN_FLOAT
24
25 #ifdef _MSC_VER
26 #pragma message("CAUTION!!: No backend type specified so testing everything.... this will take some time!!")
27 #endif
28 #ifdef __GNUC__
29 #pragma warning "CAUTION!!: No backend type specified so testing everything.... this will take some time!!"
30 #endif
31
32 #endif
33
34 #if defined(TEST_MPF) || defined(TEST_MPZ) || defined(TEST_MPQ) || defined(TEST_MPZ_BOOST_RATIONAL)
35 #include <boost/multiprecision/gmp.hpp>
36 #include <boost/multiprecision/rational_adaptor.hpp>
37 #endif
38 #ifdef TEST_CPP_DEC_FLOAT
39 #include <boost/multiprecision/cpp_dec_float.hpp>
40 #endif
41 #ifdef TEST_CPP_BIN_FLOAT
42 #include <boost/multiprecision/cpp_bin_float.hpp>
43 #endif
44 #if defined(TEST_MPFR)
45 #include <boost/multiprecision/mpfr.hpp>
46 #endif
47 #if defined(TEST_TOMMATH) || defined(TEST_TOMMATH_BOOST_RATIONAL)
48 #include <boost/multiprecision/tommath.hpp>
49 #include <boost/multiprecision/rational_adaptor.hpp>
50 #endif
51 #if defined(TEST_CPP_INT) || defined(TEST_CPP_INT_RATIONAL)
52 #include <boost/multiprecision/cpp_int.hpp>
53 #endif
54
55 #include <boost/chrono.hpp>
56 #include <vector>
57 #include <map>
58 #include <string>
59 #include <cstring>
60 #include <cctype>
61 #include <iostream>
62 #include <iomanip>
63 #include <boost/random/mersenne_twister.hpp>
64 #include <boost/random/uniform_int.hpp>
65
66 template <class Clock>
67 struct stopwatch
68 {
69 typedef typename Clock::duration duration;
70 stopwatch()
71 {
72 m_start = Clock::now();
73 }
74 duration elapsed()
75 {
76 return Clock::now() - m_start;
77 }
78 void reset()
79 {
80 m_start = Clock::now();
81 }
82
83 private:
84 typename Clock::time_point m_start;
85 };
86
87 unsigned bits_wanted; // for integer types
88
89 template <class T, int Type>
90 struct tester
91 {
92 tester()
93 {
94 a.assign(500, 0);
95 for (int i = 0; i < 500; ++i)
96 {
97 b.push_back(generate_random());
98 c.push_back(generate_random());
99 small.push_back(gen());
100 }
101 }
102 double test_add()
103 {
104 stopwatch<boost::chrono::high_resolution_clock> w;
105 for (unsigned i = 0; i < 1000; ++i)
106 {
107 for (unsigned i = 0; i < b.size(); ++i)
108 a[i] = b[i] + c[i];
109 }
110 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
111 }
112 double test_subtract()
113 {
114 stopwatch<boost::chrono::high_resolution_clock> w;
115 for (unsigned i = 0; i < 1000; ++i)
116 {
117 for (unsigned i = 0; i < b.size(); ++i)
118 a[i] = b[i] - c[i];
119 }
120 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
121 }
122 double test_add_int()
123 {
124 stopwatch<boost::chrono::high_resolution_clock> w;
125 for (unsigned i = 0; i < 1000; ++i)
126 {
127 for (unsigned i = 0; i < b.size(); ++i)
128 a[i] = b[i] + 1;
129 }
130 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
131 }
132 double test_subtract_int()
133 {
134 stopwatch<boost::chrono::high_resolution_clock> w;
135 for (unsigned i = 0; i < 1000; ++i)
136 {
137 for (unsigned i = 0; i < b.size(); ++i)
138 a[i] = b[i] - 1;
139 }
140 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
141 }
142 double test_multiply()
143 {
144 stopwatch<boost::chrono::high_resolution_clock> w;
145 for (unsigned i = 0; i < 1000; ++i)
146 {
147 for (unsigned k = 0; k < b.size(); ++k)
148 a[k] = b[k] * c[k];
149 }
150 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
151 }
152 double test_multiply_int()
153 {
154 stopwatch<boost::chrono::high_resolution_clock> w;
155 for (unsigned i = 0; i < 1000; ++i)
156 {
157 for (unsigned i = 0; i < b.size(); ++i)
158 a[i] = b[i] * 3;
159 }
160 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
161 }
162 double test_divide()
163 {
164 stopwatch<boost::chrono::high_resolution_clock> w;
165 for (unsigned i = 0; i < 1000; ++i)
166 {
167 for (unsigned i = 0; i < b.size(); ++i)
168 a[i] = b[i] / c[i] + b[i] / small[i];
169 }
170 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
171 }
172 double test_divide_int()
173 {
174 stopwatch<boost::chrono::high_resolution_clock> w;
175 for (unsigned i = 0; i < 1000; ++i)
176 {
177 for (unsigned i = 0; i < b.size(); ++i)
178 a[i] = b[i] / 3;
179 }
180 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
181 }
182 double test_str(const boost::mpl::false_&)
183 {
184 stopwatch<boost::chrono::high_resolution_clock> w;
185 for (unsigned i = 0; i < b.size(); ++i)
186 a[i] = boost::lexical_cast<T>(boost::lexical_cast<std::string>(b[i]));
187 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
188 }
189 double test_str(const boost::mpl::true_&)
190 {
191 stopwatch<boost::chrono::high_resolution_clock> w;
192 for (unsigned i = 0; i < b.size(); ++i)
193 a[i].assign(b[i].str());
194 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
195 }
196 double test_str()
197 {
198 return test_str(boost::is_class<T>());
199 }
200 //
201 // The following tests only work for integer types:
202 //
203 double test_mod()
204 {
205 stopwatch<boost::chrono::high_resolution_clock> w;
206 for (unsigned i = 0; i < 1000; ++i)
207 {
208 for (unsigned i = 0; i < b.size(); ++i)
209 a[i] = b[i] % c[i] + b[i] % small[i];
210 }
211 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
212 }
213 double test_mod_int()
214 {
215 stopwatch<boost::chrono::high_resolution_clock> w;
216 for (unsigned i = 0; i < 1000; ++i)
217 {
218 for (unsigned i = 0; i < b.size(); ++i)
219 a[i] = b[i] % 254;
220 }
221 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
222 }
223 double test_or()
224 {
225 stopwatch<boost::chrono::high_resolution_clock> w;
226 for (unsigned i = 0; i < 1000; ++i)
227 {
228 for (unsigned i = 0; i < b.size(); ++i)
229 a[i] = b[i] | c[i];
230 }
231 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
232 }
233 double test_or_int()
234 {
235 stopwatch<boost::chrono::high_resolution_clock> w;
236 for (unsigned i = 0; i < 1000; ++i)
237 {
238 for (unsigned i = 0; i < b.size(); ++i)
239 a[i] = b[i] | 234;
240 }
241 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
242 }
243 double test_and()
244 {
245 stopwatch<boost::chrono::high_resolution_clock> w;
246 for (unsigned i = 0; i < 1000; ++i)
247 {
248 for (unsigned i = 0; i < b.size(); ++i)
249 a[i] = b[i] & c[i];
250 }
251 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
252 }
253 double test_and_int()
254 {
255 stopwatch<boost::chrono::high_resolution_clock> w;
256 for (unsigned i = 0; i < 1000; ++i)
257 {
258 for (unsigned i = 0; i < b.size(); ++i)
259 a[i] = b[i] & 234;
260 }
261 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
262 }
263 double test_xor()
264 {
265 stopwatch<boost::chrono::high_resolution_clock> w;
266 for (unsigned i = 0; i < 1000; ++i)
267 {
268 for (unsigned i = 0; i < b.size(); ++i)
269 a[i] = b[i] ^ c[i];
270 }
271 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
272 }
273 double test_xor_int()
274 {
275 stopwatch<boost::chrono::high_resolution_clock> w;
276 for (unsigned i = 0; i < 1000; ++i)
277 {
278 for (unsigned i = 0; i < b.size(); ++i)
279 a[i] = b[i] ^ 234;
280 }
281 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
282 }
283 double test_complement()
284 {
285 stopwatch<boost::chrono::high_resolution_clock> w;
286 for (unsigned i = 0; i < 1000; ++i)
287 {
288 for (unsigned i = 0; i < b.size(); ++i)
289 a[i] = ~b[i];
290 }
291 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
292 }
293 double test_left_shift()
294 {
295 int max_shift = std::numeric_limits<T>::is_bounded ? std::numeric_limits<T>::digits : bits_wanted;
296 int shift = 0;
297 stopwatch<boost::chrono::high_resolution_clock> w;
298 for (unsigned i = 0; i < 1000; ++i)
299 {
300 for (unsigned i = 0; i < b.size(); ++i)
301 a[i] = b[i] << (shift++ % max_shift);
302 }
303 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
304 }
305 double test_right_shift()
306 {
307 int max_shift = 2 + std::numeric_limits<T>::is_bounded ? std::numeric_limits<T>::digits : bits_wanted;
308 int shift = 0;
309 stopwatch<boost::chrono::high_resolution_clock> w;
310 for (unsigned i = 0; i < 1000; ++i)
311 {
312 for (unsigned i = 0; i < b.size(); ++i)
313 a[i] = b[i] >> (shift++) % max_shift;
314 }
315 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
316 }
317 double test_gcd()
318 {
319 using boost::integer::gcd;
320 stopwatch<boost::chrono::high_resolution_clock> w;
321 for (unsigned i = 0; i < 1000; ++i)
322 {
323 for (unsigned i = 0; i < b.size(); ++i)
324 a[i] = gcd(b[i], c[i]);
325 }
326 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
327 }
328 double test_powm()
329 {
330 stopwatch<boost::chrono::high_resolution_clock> w;
331 for (unsigned i = 0; i < 25; ++i)
332 {
333 for (unsigned i = 0; i < b.size(); ++i)
334 a[i] = powm(b[i], b[i] / 2, c[i]);
335 }
336 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
337 }
338 double test_construct()
339 {
340 std::allocator<T> a;
341 T* pt = a.allocate(1000);
342 stopwatch<boost::chrono::high_resolution_clock> w;
343 for (unsigned i = 0; i < 1000; ++i)
344 {
345 for (unsigned i = 0; i < 1000; ++i)
346 new (pt + i) T();
347 for (unsigned i = 0; i < 1000; ++i)
348 a.destroy(pt + i);
349 }
350 double result = boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
351 a.deallocate(pt, 1000);
352 return result;
353 }
354 double test_construct_unsigned()
355 {
356 std::allocator<T> a;
357 T* pt = a.allocate(1000);
358 stopwatch<boost::chrono::high_resolution_clock> w;
359 for (unsigned i = 0; i < 1000; ++i)
360 {
361 for (unsigned i = 0; i < 1000; ++i)
362 new (pt + i) T(i);
363 for (unsigned i = 0; i < 1000; ++i)
364 a.destroy(pt + i);
365 }
366 double result = boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
367 a.deallocate(pt, 1000);
368 return result;
369 }
370 double test_construct_unsigned_ll()
371 {
372 std::allocator<T> a;
373 T* pt = a.allocate(1000);
374 stopwatch<boost::chrono::high_resolution_clock> w;
375 for (unsigned i = 0; i < 1000; ++i)
376 {
377 for (unsigned long long j = 0; j < 1000; ++j)
378 new (pt + j) T(j);
379 for (unsigned j = 0; j < 1000; ++j)
380 a.destroy(pt + j);
381 }
382 double result = boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
383 a.deallocate(pt, 1000);
384 return result;
385 }
386
387 //
388 // Hetero operations:
389 //
390 template <class U>
391 static U get_hetero_test_value(boost::mpl::false_ const&)
392 {
393 return U(2) / 3;
394 }
395 template <class U>
396 static U get_hetero_test_value(boost::mpl::true_ const&)
397 {
398 return (std::numeric_limits<U>::max)() >> 4;
399 }
400 template <class U>
401 static U get_hetero_test_value()
402 {
403 return get_hetero_test_value<U>(boost::is_integral<U>());
404 }
405 template <class U>
406 double test_multiply_hetero()
407 {
408 static const U val = get_hetero_test_value<U>();
409 stopwatch<boost::chrono::high_resolution_clock> w;
410 for (unsigned i = 0; i < 1000; ++i)
411 {
412 for (unsigned i = 0; i < b.size(); ++i)
413 a[i] = b[i] * val;
414 }
415 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
416 }
417 template <class U>
418 double test_inplace_multiply_hetero()
419 {
420 static const U val = get_hetero_test_value<U>();
421 for (unsigned i = 0; i < b.size(); ++i)
422 a[i] = b[i];
423 stopwatch<boost::chrono::high_resolution_clock> w;
424 for (unsigned i = 0; i < 1000; ++i)
425 {
426 for (unsigned i = 0; i < b.size(); ++i)
427 a[i] *= val;
428 }
429 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
430 }
431 template <class U>
432 double test_add_hetero()
433 {
434 static const U val = get_hetero_test_value<U>();
435 stopwatch<boost::chrono::high_resolution_clock> w;
436 for (unsigned i = 0; i < 1000; ++i)
437 {
438 for (unsigned i = 0; i < b.size(); ++i)
439 a[i] = b[i] + val;
440 }
441 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
442 }
443 template <class U>
444 double test_inplace_add_hetero()
445 {
446 static const U val = get_hetero_test_value<U>();
447 for (unsigned i = 0; i < b.size(); ++i)
448 a[i] = b[i];
449 stopwatch<boost::chrono::high_resolution_clock> w;
450 for (unsigned i = 0; i < 1000; ++i)
451 {
452 for (unsigned i = 0; i < b.size(); ++i)
453 a[i] += val;
454 }
455 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
456 }
457 template <class U>
458 double test_subtract_hetero()
459 {
460 static const U val = get_hetero_test_value<U>();
461 stopwatch<boost::chrono::high_resolution_clock> w;
462 for (unsigned i = 0; i < 1000; ++i)
463 {
464 for (unsigned i = 0; i < b.size(); ++i)
465 a[i] = b[i] - val;
466 }
467 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
468 }
469 template <class U>
470 double test_inplace_subtract_hetero()
471 {
472 static const U val = get_hetero_test_value<U>();
473 for (unsigned i = 0; i < b.size(); ++i)
474 a[i] = b[i];
475 stopwatch<boost::chrono::high_resolution_clock> w;
476 for (unsigned i = 0; i < 1000; ++i)
477 {
478 for (unsigned i = 0; i < b.size(); ++i)
479 a[i] -= val;
480 }
481 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
482 }
483 template <class U>
484 double test_divide_hetero()
485 {
486 static const U val = get_hetero_test_value<U>();
487 stopwatch<boost::chrono::high_resolution_clock> w;
488 for (unsigned i = 0; i < 1000; ++i)
489 {
490 for (unsigned i = 0; i < b.size(); ++i)
491 a[i] = b[i] / val;
492 }
493 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
494 }
495 template <class U>
496 double test_inplace_divide_hetero()
497 {
498 static const U val = get_hetero_test_value<U>();
499 for (unsigned i = 0; i < b.size(); ++i)
500 a[i] = b[i];
501 stopwatch<boost::chrono::high_resolution_clock> w;
502 for (unsigned i = 0; i < 1000; ++i)
503 {
504 for (unsigned i = 0; i < b.size(); ++i)
505 a[i] /= val;
506 }
507 return boost::chrono::duration_cast<boost::chrono::duration<double> >(w.elapsed()).count();
508 }
509
510 private:
511 T generate_random()
512 {
513 return generate_random(boost::mpl::int_<Type>());
514 }
515 T generate_random(const boost::mpl::int_<boost::multiprecision::number_kind_floating_point>&)
516 {
517 T val = gen();
518 T prev_val = -1;
519 while (val != prev_val)
520 {
521 val *= (gen.max)();
522 prev_val = val;
523 val += gen();
524 }
525 int e;
526 val = frexp(val, &e);
527
528 typedef typename T::backend_type::exponent_type e_type;
529 static boost::random::uniform_int_distribution<e_type> ui(-30, 30);
530 return ldexp(val, static_cast<int>(ui(gen)));
531 }
532 T generate_random(const boost::mpl::int_<boost::multiprecision::number_kind_integer>&)
533 {
534 typedef boost::random::mt19937::result_type random_type;
535
536 T max_val;
537 unsigned digits;
538 if (std::numeric_limits<T>::is_bounded)
539 {
540 max_val = (std::numeric_limits<T>::max)();
541 digits = std::numeric_limits<T>::digits;
542 }
543 else
544 {
545 max_val = T(1) << bits_wanted;
546 digits = bits_wanted;
547 }
548
549 unsigned bits_per_r_val = std::numeric_limits<random_type>::digits - 1;
550 while ((random_type(1) << bits_per_r_val) > (gen.max)())
551 --bits_per_r_val;
552
553 unsigned terms_needed = digits / bits_per_r_val + 1;
554
555 T val = 0;
556 for (unsigned i = 0; i < terms_needed; ++i)
557 {
558 val *= (gen.max)();
559 val += gen();
560 }
561 val %= max_val;
562 return val;
563 }
564 T generate_random(const boost::mpl::int_<boost::multiprecision::number_kind_rational>&)
565 {
566 typedef boost::random::mt19937::result_type random_type;
567 typedef typename boost::multiprecision::component_type<T>::type IntType;
568
569 IntType max_val;
570 unsigned digits;
571 if (std::numeric_limits<IntType>::is_bounded)
572 {
573 max_val = (std::numeric_limits<IntType>::max)();
574 digits = std::numeric_limits<IntType>::digits;
575 }
576 else
577 {
578 max_val = IntType(1) << bits_wanted;
579 digits = bits_wanted;
580 }
581
582 unsigned bits_per_r_val = std::numeric_limits<random_type>::digits - 1;
583 while ((random_type(1) << bits_per_r_val) > (gen.max)())
584 --bits_per_r_val;
585
586 unsigned terms_needed = digits / bits_per_r_val + 1;
587
588 IntType val = 0;
589 IntType denom = 0;
590 for (unsigned i = 0; i < terms_needed; ++i)
591 {
592 val *= (gen.max)();
593 val += gen();
594 }
595 for (unsigned i = 0; i < terms_needed; ++i)
596 {
597 denom *= (gen.max)();
598 denom += gen();
599 }
600 if (denom == 0)
601 denom = 1;
602 val %= max_val;
603 denom %= max_val;
604 return T(val, denom);
605 }
606 std::vector<T> a, b, c, small;
607 static boost::random::mt19937 gen;
608 };
609
610 template <class N, int V>
611 boost::random::mt19937 tester<N, V>::gen;
612
613 const char* category_name(const boost::mpl::int_<boost::multiprecision::number_kind_integer>&)
614 {
615 return "integer";
616 }
617 const char* category_name(const boost::mpl::int_<boost::multiprecision::number_kind_floating_point>&)
618 {
619 return "float";
620 }
621 const char* category_name(const boost::mpl::int_<boost::multiprecision::number_kind_rational>&)
622 {
623 return "rational";
624 }
625
626 //
627 // Keys in order are:
628 // Category
629 // Operator
630 // Type
631 // Precision
632 // Time
633 //
634 std::map<std::string, std::map<std::string, std::map<std::string, std::map<int, double> > > > result_table;
635
636 void report_result(const char* cat, const char* type, const char* op, unsigned precision, double time)
637 {
638 std::cout << std::left << std::setw(15) << type << std::setw(10) << precision << std::setw(35) << op << time << std::endl;
639 result_table[cat][op][type][precision] = time;
640 }
641
642 template <class Number, int N>
643 void test_int_ops(tester<Number, N>& t, const char* type, unsigned precision, const boost::mpl::int_<boost::multiprecision::number_kind_integer>&)
644 {
645 const char* cat = "integer";
646 report_result(cat, type, "%", precision, t.test_mod());
647 report_result(cat, type, "|", precision, t.test_or());
648 report_result(cat, type, "&", precision, t.test_and());
649 report_result(cat, type, "^", precision, t.test_xor());
650 //report_result(cat, type, "~", precision, t.test_complement());
651 report_result(cat, type, "<<", precision, t.test_left_shift());
652 report_result(cat, type, ">>", precision, t.test_right_shift());
653 // integer ops:
654 report_result(cat, type, "%(int)", precision, t.test_mod_int());
655 report_result(cat, type, "|(int)", precision, t.test_or_int());
656 report_result(cat, type, "&(int)", precision, t.test_and_int());
657 report_result(cat, type, "^(int)", precision, t.test_xor_int());
658 report_result(cat, type, "gcd", precision, t.test_gcd());
659 report_result(cat, type, "powm", precision, t.test_powm());
660 }
661 template <class Number, int N, class U>
662 void test_int_ops(tester<Number, N>& t, const char* type, unsigned precision, const U&)
663 {
664 }
665
666 template <class Number>
667 void test(const char* type, unsigned precision)
668 {
669 bits_wanted = precision;
670 tester<Number, boost::multiprecision::number_category<Number>::value> t;
671 const char* cat = category_name(typename boost::multiprecision::number_category<Number>::type());
672 //
673 // call t.test_multiply() first so that the destination operands are
674 // forced to perform whatever memory allocation may be needed. That way
675 // we measure only algorithm performance, and not memory allocation effects.
676 //
677 t.test_multiply();
678 //
679 // Now the actual tests:
680 //
681 report_result(cat, type, "+", precision, t.test_add());
682 report_result(cat, type, "-", precision, t.test_subtract());
683 report_result(cat, type, "*", precision, t.test_multiply());
684 report_result(cat, type, "/", precision, t.test_divide());
685 report_result(cat, type, "str", precision, t.test_str());
686 // integer ops:
687 report_result(cat, type, "+(int)", precision, t.test_add_int());
688 report_result(cat, type, "-(int)", precision, t.test_subtract_int());
689 report_result(cat, type, "*(int)", precision, t.test_multiply_int());
690 report_result(cat, type, "/(int)", precision, t.test_divide_int());
691 // construction and destruction:
692 report_result(cat, type, "construct", precision, t.test_construct());
693 report_result(cat, type, "construct(unsigned)", precision, t.test_construct_unsigned());
694 report_result(cat, type, "construct(unsigned long long)", precision, t.test_construct_unsigned_ll());
695 test_int_ops(t, type, precision, typename boost::multiprecision::number_category<Number>::type());
696 // Hetero ops:
697 report_result(cat, type, "+(unsigned long long)", precision, t.template test_add_hetero<unsigned long long>());
698 report_result(cat, type, "-(unsigned long long)", precision, t.template test_subtract_hetero<unsigned long long>());
699 report_result(cat, type, "*(unsigned long long)", precision, t.template test_multiply_hetero<unsigned long long>());
700 report_result(cat, type, "/(unsigned long long)", precision, t.template test_divide_hetero<unsigned long long>());
701 report_result(cat, type, "+=(unsigned long long)", precision, t.template test_inplace_add_hetero<unsigned long long>());
702 report_result(cat, type, "-=(unsigned long long)", precision, t.template test_inplace_subtract_hetero<unsigned long long>());
703 report_result(cat, type, "*=(unsigned long long)", precision, t.template test_inplace_multiply_hetero<unsigned long long>());
704 report_result(cat, type, "/=(unsigned long long)", precision, t.template test_inplace_divide_hetero<unsigned long long>());
705 }
706
707 void quickbook_results()
708 {
709 //
710 // Keys in order are:
711 // Category
712 // Operator
713 // Type
714 // Precision
715 // Time
716 //
717 typedef std::map<std::string, std::map<std::string, std::map<std::string, std::map<int, double> > > >::const_iterator category_iterator;
718 typedef std::map<std::string, std::map<std::string, std::map<int, double> > >::const_iterator operator_iterator;
719 typedef std::map<std::string, std::map<int, double> >::const_iterator type_iterator;
720 typedef std::map<int, double>::const_iterator precision_iterator;
721
722 for (category_iterator i = result_table.begin(); i != result_table.end(); ++i)
723 {
724 std::string cat = i->first;
725 cat[0] = std::toupper(cat[0]);
726 std::cout << "[section:" << i->first << "_performance " << cat << " Type Perfomance]" << std::endl;
727
728 for (operator_iterator j = i->second.begin(); j != i->second.end(); ++j)
729 {
730 std::string op = j->first;
731 std::cout << "[table Operator " << op << std::endl;
732 std::cout << "[[Backend]";
733
734 for (precision_iterator k = j->second.begin()->second.begin(); k != j->second.begin()->second.end(); ++k)
735 {
736 std::cout << "[" << k->first << " Bits]";
737 }
738 std::cout << "]\n";
739
740 std::vector<double> best_times(j->second.begin()->second.size(), (std::numeric_limits<double>::max)());
741 for (unsigned m = 0; m < j->second.begin()->second.size(); ++m)
742 {
743 for (type_iterator k = j->second.begin(); k != j->second.end(); ++k)
744 {
745 precision_iterator l = k->second.begin();
746 std::advance(l, m);
747 if (best_times[m] > l->second)
748 best_times[m] = l->second ? l->second : best_times[m];
749 }
750 }
751
752 for (type_iterator k = j->second.begin(); k != j->second.end(); ++k)
753 {
754 std::cout << "[[" << k->first << "]";
755
756 unsigned m = 0;
757 for (precision_iterator l = k->second.begin(); l != k->second.end(); ++l)
758 {
759 double rel_time = l->second / best_times[m];
760 if (rel_time == 1)
761 std::cout << "[[*" << rel_time << "]";
762 else
763 std::cout << "[" << rel_time;
764 std::cout << " (" << l->second << "s)]";
765 ++m;
766 }
767
768 std::cout << "]\n";
769 }
770
771 std::cout << "]\n";
772 }
773
774 std::cout << "[endsect]" << std::endl;
775 }
776 }
777
778 int main()
779 {
780 #ifdef TEST_INT64
781 test<boost::uint64_t>("boost::uint64_t", 64);
782 #endif
783 #ifdef TEST_MPF
784 test<boost::multiprecision::mpf_float_50>("gmp_float", 50);
785 test<boost::multiprecision::mpf_float_100>("gmp_float", 100);
786 test<boost::multiprecision::mpf_float_500>("gmp_float", 500);
787 #endif
788 #ifdef TEST_MPZ
789 test<boost::multiprecision::mpz_int>("gmp_int", 128);
790 test<boost::multiprecision::mpz_int>("gmp_int", 256);
791 test<boost::multiprecision::mpz_int>("gmp_int", 512);
792 test<boost::multiprecision::mpz_int>("gmp_int", 1024);
793 #endif
794 #ifdef TEST_CPP_INT
795 //test<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<64, 64, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>, boost::multiprecision::et_off> >("cpp_int(unsigned, fixed)", 64);
796 //test<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<64, 64, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>, boost::multiprecision::et_off> >("cpp_int(fixed)", 64);
797 test<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<128, 128, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>, boost::multiprecision::et_off> >("cpp_int(fixed)", 128);
798 test<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>, boost::multiprecision::et_off> >("cpp_int(fixed)", 256);
799 test<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<512, 512, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>, boost::multiprecision::et_off> >("cpp_int(fixed)", 512);
800 test<boost::multiprecision::number<boost::multiprecision::cpp_int_backend<1024, 1024, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>, boost::multiprecision::et_off> >("cpp_int(fixed)", 1024);
801
802 test<boost::multiprecision::cpp_int>("cpp_int", 128);
803 test<boost::multiprecision::cpp_int>("cpp_int", 256);
804 test<boost::multiprecision::cpp_int>("cpp_int", 512);
805 test<boost::multiprecision::cpp_int>("cpp_int", 1024);
806 #endif
807 #ifdef TEST_CPP_INT_RATIONAL
808 test<boost::multiprecision::cpp_rational>("cpp_rational", 128);
809 test<boost::multiprecision::cpp_rational>("cpp_rational", 256);
810 test<boost::multiprecision::cpp_rational>("cpp_rational", 512);
811 test<boost::multiprecision::cpp_rational>("cpp_rational", 1024);
812 #endif
813 #ifdef TEST_MPQ
814 test<boost::multiprecision::mpq_rational>("mpq_rational", 128);
815 test<boost::multiprecision::mpq_rational>("mpq_rational", 256);
816 test<boost::multiprecision::mpq_rational>("mpq_rational", 512);
817 test<boost::multiprecision::mpq_rational>("mpq_rational", 1024);
818 #endif
819 #ifdef TEST_TOMMATH
820 test<boost::multiprecision::tom_int>("tommath_int", 128);
821 test<boost::multiprecision::tom_int>("tommath_int", 256);
822 test<boost::multiprecision::tom_int>("tommath_int", 512);
823 test<boost::multiprecision::tom_int>("tommath_int", 1024);
824 /*
825 //
826 // These are actually too slow to test!!!
827 //
828 test<boost::multiprecision::tom_rational>("tom_rational", 128);
829 test<boost::multiprecision::tom_rational>("tom_rational", 256);
830 test<boost::multiprecision::tom_rational>("tom_rational", 512);
831 test<boost::multiprecision::tom_rational>("tom_rational", 1024);
832 */
833 #endif
834 #ifdef TEST_CPP_DEC_FLOAT
835 test<boost::multiprecision::cpp_dec_float_50>("cpp_dec_float", 50);
836 test<boost::multiprecision::cpp_dec_float_100>("cpp_dec_float", 100);
837 test<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<500> > >("cpp_dec_float", 500);
838 #endif
839 #ifdef TEST_CPP_BIN_FLOAT
840 test<boost::multiprecision::cpp_bin_float_50>("cpp_bin_float", 50);
841 test<boost::multiprecision::cpp_bin_float_100>("cpp_bin_float", 100);
842 test<boost::multiprecision::number<boost::multiprecision::cpp_bin_float<500> > >("cpp_bin_float", 500);
843 #endif
844 #ifdef TEST_MPFR
845 test<boost::multiprecision::mpfr_float_50>("mpfr_float", 50);
846 test<boost::multiprecision::mpfr_float_100>("mpfr_float", 100);
847 test<boost::multiprecision::mpfr_float_500>("mpfr_float", 500);
848 #endif
849 quickbook_results();
850 return 0;
851 }