minmax_timer.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. // (C) Copyright Herve Bronnimann 2004.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #include <utility>
  6. #include <functional>
  7. #include <algorithm>
  8. #include <numeric>
  9. #include <iterator>
  10. #include <vector>
  11. #include <list>
  12. #include <set>
  13. #include <iostream>
  14. // What's the proper BOOST_ flag for <iomanip.h> vs <ios>
  15. #include <iomanip>
  16. #include <boost/timer.hpp>
  17. #include <boost/algorithm/minmax.hpp>
  18. template <class T1, class T2>
  19. void tie(std::pair<T1, T2> p, T1& min, T2& max)
  20. {
  21. min = p.first; max = p.second;
  22. }
  23. template <class Value>
  24. struct less_count : std::less<Value> {
  25. less_count(less_count<Value> const& lc) : _M_counter(lc._M_counter) {}
  26. less_count(int& counter) : _M_counter(counter) {}
  27. bool operator()(Value const& a, Value const& b) const {
  28. ++_M_counter;
  29. return std::less<Value>::operator()(a,b);
  30. }
  31. void reset() {
  32. _M_counter = 0;
  33. }
  34. private:
  35. int& _M_counter;
  36. };
  37. inline int opt_min_count(int n) {
  38. return (n==0) ? 0 : n-1;
  39. }
  40. inline int opt_minmax_count(int n) {
  41. if (n < 2) return 0;
  42. if (n == 2) return 1;
  43. return (n%2 == 0) ? 3*(n/2)-1 : 3*(n/2)+1;
  44. }
  45. inline int opt_boost_minmax_count(int n) {
  46. if (n < 2) return 0;
  47. if (n == 2) return 1;
  48. return (n%2 == 0) ? 3*(n/2)-2 : 3*(n/2);
  49. }
  50. int repeats = 10;
  51. #define TIMER( n, cmd , cmdname ) \
  52. t.restart(); \
  53. for (int i=0; i<repeats; ++i) { cmd ; } \
  54. std::cout << " " << std::setprecision(4) \
  55. << (double)n*repeats/t.elapsed()/1.0E6 \
  56. << "M items/sec " << cmdname << "\n"
  57. #define CTIMER( n, cmd , cmdname, count, opt ) \
  58. t.restart(); lc.reset(); \
  59. for (int i=0; i<repeats; ++i) { cmd ; } \
  60. std::cout << " " << std::setprecision(4) \
  61. << (double)n*repeats/t.elapsed()/1.0E6 \
  62. << "M items/sec " << cmdname \
  63. << " ("<< (count)/repeats << " vs " << opt << ")\n"
  64. template <class CIterator>
  65. void test_minmax_element(CIterator first, CIterator last, int n, char* name)
  66. {
  67. typedef typename std::iterator_traits<CIterator>::value_type vtype;
  68. boost::timer t;
  69. std::cout << " ON " << name << " WITH OPERATOR<()\n";
  70. TIMER( n, std::min_element(first, last),
  71. "std::min_element" << name << "");
  72. TIMER( n, std::max_element(first, last),
  73. "std::max_element" << name << "");
  74. TIMER( n, boost::first_min_element(first, last),
  75. "boost::first_min_element" << name << "");
  76. TIMER( n, boost::last_min_element(first, last),
  77. "boost::last_min_element" << name << " ");
  78. TIMER( n, boost::first_max_element(first, last),
  79. "boost::first_max_element" << name << "");
  80. TIMER( n, boost::last_max_element(first, last),
  81. "boost::last_max_element" << name << " ");
  82. TIMER( n, boost::minmax_element(first, last),
  83. "boost::minmax_element" << name << " ");
  84. TIMER( n, boost::first_min_last_max_element(first, last),
  85. "boost::first_min_last_max_element" << name << "");
  86. TIMER( n, boost::last_min_first_max_element(first, last),
  87. "boost::last_min_first_max_element" << name << "");
  88. TIMER( n, boost::last_min_last_max_element(first, last),
  89. "boost::last_min_last_max_element" << name << " ");
  90. #define pred std::bind2nd( std::greater<vtype>(), vtype(10) )
  91. TIMER( n, boost::min_element_if(first, last, pred),
  92. "boost::min_element_if" << name << "");
  93. TIMER( n, boost::max_element_if(first, last, pred),
  94. "boost::max_element_if" << name << "");
  95. TIMER( n, std::min_element(boost::make_filter_iterator(first, last, pred),
  96. boost::make_filter_iterator(last, last, pred)),
  97. "std::min_element_with_filter_iterator" << name << "");
  98. TIMER( n, std::max_element(boost::make_filter_iterator(first, last, pred),
  99. boost::make_filter_iterator(last, last, pred)),
  100. "std::max_element_if_with_filter_iterator" << name << "");
  101. #undef pred
  102. int counter = 0;
  103. less_count<vtype> lc(counter);
  104. std::cout << " ON " << name << " WITH LESS<> AND COUNTING COMPARISONS\n";
  105. CTIMER( n, std::min_element(first, last, lc),
  106. "std::min_element" << name << " ",
  107. counter, opt_min_count(n) );
  108. CTIMER( n, std::max_element(first, last, lc),
  109. "std::max_element" << name << " ",
  110. counter, opt_min_count(n) );
  111. CTIMER( n, boost::first_min_element(first, last, lc),
  112. "boost::first_min_element" << name << "",
  113. counter, opt_min_count(n) );
  114. CTIMER( n, boost::last_min_element(first, last, lc),
  115. "boost::last_max_element" << name << " ",
  116. counter, opt_min_count(n) );
  117. CTIMER( n, boost::first_max_element(first, last, lc),
  118. "boost::first_min_element" << name << "",
  119. counter, opt_min_count(n) );
  120. CTIMER( n, boost::last_max_element(first, last, lc),
  121. "boost::last_max_element" << name << " ",
  122. counter, opt_min_count(n) );
  123. CTIMER( n, boost::minmax_element(first, last, lc),
  124. "boost::minmax_element" << name << " ",
  125. counter, opt_minmax_count(n) );
  126. CTIMER( n, boost::first_min_last_max_element(first, last, lc),
  127. "boost::first_min_last_max_element" << name << "",
  128. counter, opt_boost_minmax_count(n) );
  129. CTIMER( n, boost::last_min_first_max_element(first, last, lc),
  130. "boost::last_min_first_max_element" << name << "",
  131. counter, opt_boost_minmax_count(n) );
  132. CTIMER( n, boost::last_min_last_max_element(first, last, lc),
  133. "boost::last_min_last_max_element" << name << " ",
  134. counter, opt_minmax_count(n) );
  135. }
  136. template <class Container, class Iterator, class Value>
  137. void test_container(Iterator first, Iterator last, int n, char* name)
  138. {
  139. Container c(first, last);
  140. typename Container::iterator fit(c.begin()), lit(c.end());
  141. test_minmax_element(fit, lit, n, name);
  142. }
  143. template <class Iterator>
  144. void test_range(Iterator first, Iterator last, int n)
  145. {
  146. typedef typename std::iterator_traits<Iterator>::value_type Value;
  147. // Test various containers with these values
  148. test_container< std::vector<Value>, Iterator, Value >(first, last, n, "<vector>");
  149. #ifndef ONLY_VECTOR
  150. test_container< std::list<Value>, Iterator, Value >(first, last, n, "<list> ");
  151. test_container< std::multiset<Value>, Iterator, Value >(first, last, n, "<set> ");
  152. #endif
  153. }
  154. template <class Value>
  155. void test(int n)
  156. {
  157. // Populate test vector with identical values
  158. std::cout << "IDENTICAL VALUES... \n";
  159. std::vector<Value> test_vector(n, Value(1));
  160. typename std::vector<Value>::iterator first( test_vector.begin() );
  161. typename std::vector<Value>::iterator last( test_vector.end() );
  162. test_range(first, last, n);
  163. // Populate test vector with two values
  164. std::cout << "TWO DISTINCT VALUES...\n";
  165. typename std::vector<Value>::iterator middle( first + n/2 );
  166. std::fill(middle, last, Value(2));
  167. test_range(first, last, n);
  168. // Populate test vector with increasing values
  169. std::cout << "INCREASING VALUES... \n";
  170. std::fill(first, last, Value(1));
  171. std::accumulate(first, last, Value(0));
  172. test_range(first, last, n);
  173. // Populate test vector with decreasing values
  174. std::cout << "DECREASING VALUES... \n";
  175. std::reverse(first, last);
  176. test_range(first, last, n);
  177. // Populate test vector with random values
  178. std::cout << "RANDOM VALUES... \n";
  179. std::random_shuffle(first, last);
  180. test_range(first, last, n);
  181. }
  182. int
  183. main(char argc, char** argv)
  184. {
  185. int n = 100;
  186. if (argc > 1) n = atoi(argv[1]);
  187. if (argc > 2) repeats = atoi(argv[2]);
  188. test<int>(n);
  189. return 0;
  190. }