miller_rabin_performance.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. ///////////////////////////////////////////////////////////////
  2. // Copyright 2012 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. #if !defined(TEST_MPZ) && !defined(TEST_TOMMATH) && !defined(TEST_CPP_INT)
  7. #define TEST_MPZ
  8. #define TEST_TOMMATH
  9. #define TEST_CPP_INT
  10. #endif
  11. #ifdef TEST_MPZ
  12. #include <boost/multiprecision/gmp.hpp>
  13. #endif
  14. #ifdef TEST_TOMMATH
  15. #include <boost/multiprecision/tommath.hpp>
  16. #endif
  17. #ifdef TEST_CPP_INT
  18. #include <boost/multiprecision/cpp_int.hpp>
  19. #endif
  20. #include <boost/multiprecision/miller_rabin.hpp>
  21. #include <boost/chrono.hpp>
  22. #include <map>
  23. template <class Clock>
  24. struct stopwatch
  25. {
  26. typedef typename Clock::duration duration;
  27. stopwatch()
  28. {
  29. m_start = Clock::now();
  30. }
  31. duration elapsed()
  32. {
  33. return Clock::now() - m_start;
  34. }
  35. void reset()
  36. {
  37. m_start = Clock::now();
  38. }
  39. private:
  40. typename Clock::time_point m_start;
  41. };
  42. unsigned allocation_count = 0;
  43. void* (*alloc_func_ptr)(size_t);
  44. void* (*realloc_func_ptr)(void*, size_t, size_t);
  45. void (*free_func_ptr)(void*, size_t);
  46. void* alloc_func(size_t n)
  47. {
  48. ++allocation_count;
  49. return (*alloc_func_ptr)(n);
  50. }
  51. void free_func(void* p, size_t n)
  52. {
  53. (*free_func_ptr)(p, n);
  54. }
  55. void* realloc_func(void* p, size_t old, size_t n)
  56. {
  57. ++allocation_count;
  58. return (*realloc_func_ptr)(p, old, n);
  59. }
  60. #ifdef TEST_MPZ
  61. boost::chrono::duration<double> test_miller_rabin_gmp()
  62. {
  63. using namespace boost::random;
  64. using namespace boost::multiprecision;
  65. stopwatch<boost::chrono::high_resolution_clock> c;
  66. independent_bits_engine<mt11213b, 256, mpz_int> gen;
  67. for (unsigned i = 0; i < 1000; ++i)
  68. {
  69. mpz_int n = gen();
  70. mpz_probab_prime_p(n.backend().data(), 25);
  71. }
  72. return c.elapsed();
  73. }
  74. #endif
  75. std::map<std::string, double> results;
  76. double min_time = (std::numeric_limits<double>::max)();
  77. template <class IntType>
  78. boost::chrono::duration<double> test_miller_rabin(const char* name)
  79. {
  80. using namespace boost::random;
  81. stopwatch<boost::chrono::high_resolution_clock> c;
  82. independent_bits_engine<mt11213b, 256, IntType> gen;
  83. //
  84. // We must use a different generator for the tests and number generation, otherwise
  85. // we get false positives.
  86. //
  87. mt19937 gen2;
  88. unsigned result_count = 0;
  89. for (unsigned i = 0; i < 1000; ++i)
  90. {
  91. IntType n = gen();
  92. if (boost::multiprecision::miller_rabin_test(n, 25, gen2))
  93. ++result_count;
  94. }
  95. boost::chrono::duration<double> t = c.elapsed();
  96. double d = t.count();
  97. if (d < min_time)
  98. min_time = d;
  99. results[name] = d;
  100. std::cout << "Time for " << std::setw(30) << std::left << name << " = " << d << std::endl;
  101. std::cout << "Number of primes found = " << result_count << std::endl;
  102. return t;
  103. }
  104. void generate_quickbook()
  105. {
  106. std::cout << "[table\n[[Integer Type][Relative Performance (Actual time in parenthesis)]]\n";
  107. std::map<std::string, double>::const_iterator i(results.begin()), j(results.end());
  108. while (i != j)
  109. {
  110. double rel = i->second / min_time;
  111. std::cout << "[[" << i->first << "][" << rel << "(" << i->second << "s)]]\n";
  112. ++i;
  113. }
  114. std::cout << "]\n";
  115. }
  116. int main()
  117. {
  118. using namespace boost::multiprecision;
  119. #ifdef TEST_CPP_INT
  120. test_miller_rabin<number<cpp_int_backend<>, et_off> >("cpp_int (no Expression templates)");
  121. test_miller_rabin<cpp_int>("cpp_int");
  122. test_miller_rabin<number<cpp_int_backend<128> > >("cpp_int (128-bit cache)");
  123. test_miller_rabin<number<cpp_int_backend<256> > >("cpp_int (256-bit cache)");
  124. test_miller_rabin<number<cpp_int_backend<512> > >("cpp_int (512-bit cache)");
  125. test_miller_rabin<number<cpp_int_backend<1024> > >("cpp_int (1024-bit cache)");
  126. test_miller_rabin<int1024_t>("int1024_t");
  127. test_miller_rabin<checked_int1024_t>("checked_int1024_t");
  128. #endif
  129. #ifdef TEST_MPZ
  130. test_miller_rabin<number<gmp_int, et_off> >("mpz_int (no Expression templates)");
  131. test_miller_rabin<mpz_int>("mpz_int");
  132. std::cout << "Time for mpz_int (native Miller Rabin Test) = " << test_miller_rabin_gmp() << std::endl;
  133. #endif
  134. #ifdef TEST_TOMMATH
  135. test_miller_rabin<number<boost::multiprecision::tommath_int, et_off> >("tom_int (no Expression templates)");
  136. test_miller_rabin<boost::multiprecision::tom_int>("tom_int");
  137. #endif
  138. generate_quickbook();
  139. return 0;
  140. }