performance_test.cpp 31 KB

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