Index: trunk/libstdc++-v3/include/bits/uniform_int_dist.h =================================================================== --- trunk/libstdc++-v3/include/bits/uniform_int_dist.h (revision 275324) +++ trunk/libstdc++-v3/include/bits/uniform_int_dist.h (working copy) @@ -33,6 +33,7 @@ #include #include +#include namespace std _GLIBCXX_VISIBILITY(default) { @@ -242,15 +243,59 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION if (__urngrange > __urange) { - // downscaling - const __uctype __uerange = __urange + 1; // __urange can be zero - const __uctype __scaling = __urngrange / __uerange; - const __uctype __past = __uerange * __scaling; - do - __ret = __uctype(__urng()) - __urngmin; - while (__ret >= __past); - __ret /= __scaling; - } + const __uctype __uerange = __urange + 1; // __urange can be zero +#if _GLIBCXX_USE_INT128 == 1 + if(sizeof(__uctype) == sizeof(uint64_t) and + (__urngrange == numeric_limits::max())) + { + // 64-bit case + // reference: Fast Random Integer Generation in an Interval + // ACM Transactions on Modeling and Computer Simulation 29 (1), 2019 + // https://arxiv.org/abs/1805.10941 + __uint128_t __product = (__uctype(__urng()) - __urngmin) * __uerange; + uint64_t __lsb = uint64_t(__product); + if(__lsb < __uerange) + { + uint64_t __threshold = -__uerange % __uerange; + while (__lsb < __threshold) + { + __product = (__uctype(__urng()) - __urngmin) * __uerange; + __lsb = uint64_t(__product); + } + } + __ret = __product >> 64; + } + else +#endif // _GLIBCXX_USE_INT128 == 1 + if(sizeof(__uctype) == sizeof(uint32_t) + and (__urngrange == numeric_limits::max()) ) + { + // 32-bit case + // reference: Fast Random Integer Generation in an Interval + // ACM Transactions on Modeling and Computer Simulation 29 (1), 2019 + // https://arxiv.org/abs/1805.10941 + uint64_t __product = (__uctype(__urng()) - __urngmin) * __uerange; + uint32_t __lsb = uint32_t(__product); + if(__lsb < __uerange) { + uint64_t __threshold = -__uerange % __uerange; + while (__lsb < __threshold) { + __product = (__uctype(__urng()) - __urngmin) * __uerange; + __lsb = uint32_t(__product); + } + } + __ret = __product >> 32; + } + else + { + // fallback case (2 divisions) + const __uctype __scaling = __urngrange / __uerange; + const __uctype __past = __uerange * __scaling; + do + __ret = __uctype(__urng()) - __urngmin; + while (__ret >= __past); + __ret /= __scaling; + } + } else if (__urngrange < __urange) { // upscaling