Index: libcxx/include/__random/uniform_int_distribution.h =================================================================== --- libcxx/include/__random/uniform_int_distribution.h +++ libcxx/include/__random/uniform_int_distribution.h @@ -237,8 +237,12 @@ return __p.a(); const size_t _Dt = numeric_limits<_UIntType>::digits; typedef __independent_bits_engine<_URNG, _UIntType> _Eng; + typedef typename _URNG::result_type _URNG_RT; + _URNG_RT _Rg = _URNG::max() - _URNG::min() + _URNG_RT(1); if (_Rp == 0) return static_cast(_Eng(__g, _Dt)()); + else if (_Rg != 0 && _Rg % _Rp == 0) + return static_cast(__p.a() + (__g() / (_Rg / _Rp))); size_t __w = _Dt - __countl_zero(_Rp) - 1; if ((_Rp & (numeric_limits<_UIntType>::max() >> (_Dt - __w))) != 0) ++__w; Index: libcxx/test/std/numerics/rand/rand.dis/rand.dist.uni/rand.dist.uni.int/no_wasted_entropy.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/std/numerics/rand/rand.dis/rand.dist.uni/rand.dist.uni.int/no_wasted_entropy.pass.cpp @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: c++03 + +// + +// template +// class uniform_int_distribution + +// template result_type operator()(_URNG& g); + +#include +#include + +#include "test_macros.h" + +// Cycles through the range [0, 12) backwards. +struct uniform_rbg { + using result_type = unsigned; + + static constexpr unsigned min() noexcept { return 0; } + static constexpr unsigned max() noexcept { return 11; } + + unsigned operator()() { + unsigned result = 11 - count; + count = (count + 1) % 12; + ++num_calls; + return result; + } + + unsigned count = 0; + unsigned num_calls = 0; +}; + +// Returns numbers in the range [0, 24) which always have the lowest two bits set. +struct non_uniform_rbg { + using result_type = unsigned; + + static constexpr unsigned min() noexcept { return 0; } + static constexpr unsigned max() noexcept { return 23; } + + unsigned operator()() { + // Bail out in case of an endless loop: + assert(num_calls <= 100); + + unsigned result = count | 3; + count = (count + 1) % 24; + ++num_calls; + return result; + } + + unsigned count = 0; + unsigned num_calls = 0; +}; + +int main() { + { + uniform_rbg urbg; + std::uniform_int_distribution uni(0, 2); + int i = uni(urbg); + assert(0 <= i && i < 3); + assert(urbg.num_calls == 1); + } + + { + non_uniform_rbg nurbg; + std::uniform_int_distribution uni(0, 2); + int i = uni(nurbg); + assert(0 <= i && i < 3); + assert(nurbg.num_calls == 1); + } + + return 0; +}