Hi, The attached patch makes std::shuffle about 33% faster for the following testcase:
#include <random> #include <iostream> #include <algorithm> int main() { std::mt19937 gen; std::vector<int> v; v.reserve(10000); for (int i = 0; i != 10000; ++i) { v.push_back(i); std::shuffle(v.begin(), v.end(), gen); } std::cout << v.front() << '\n'; } It achieves this by avoiding std::uniform_int_distribution when the generator's range is large enough, which is almost always the case. This helps a lot, because std::uniform_int_distribution::op() recomputes scaling factors every time. Thoughts? Thanks, Eelis
Index: libstdc++-v3/include/bits/stl_algo.h =================================================================== --- libstdc++-v3/include/bits/stl_algo.h (revision 235680) +++ libstdc++-v3/include/bits/stl_algo.h (working copy) @@ -3738,12 +3738,40 @@ _DistanceType; typedef typename std::make_unsigned<_DistanceType>::type __ud_type; - typedef typename std::uniform_int_distribution<__ud_type> __distr_type; - typedef typename __distr_type::param_type __p_type; - __distr_type __d; + typedef typename std::remove_reference<_UniformRandomNumberGenerator>::type _Gen; + typedef typename std::common_type<typename _Gen::result_type, __ud_type>::type __uc_type; - for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) - std::iter_swap(__i, __first + __d(__g, __p_type(0, __i - __first))); + const __uc_type __urngrange = + _Gen::max() - _Gen::min() + 1; // +1 because the generator range is inclusive + + const __uc_type __urange = __uc_type(__last - __first); + + if (__urngrange >= __urange) + { + const __uc_type __scaling = __urngrange / __urange; + const __uc_type __past = __urange * __scaling; + + for (_RandomAccessIterator __i = __first; __i != __last; ++__i) + { + __uc_type __j; + do + { + __j = __uc_type(__g()) - _Gen::min(); + } + while (__j >= __past); + + std::iter_swap(__i, __first + __j / __scaling); + } + } + else + { + typedef typename std::uniform_int_distribution<__ud_type> __distr_type; + typedef typename __distr_type::param_type __p_type; + __distr_type __d; + + for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + std::iter_swap(__i, __first + __d(__g, __p_type(0, __i - __first))); + } } #endif