Changes in v2: * Re-initialize inner loop variables. * Compute result optimistically, check outcome reliably.
Changes: * Whitespace tweaks aside, this just strips out the existing fixup and wraps the generator in a do .. while loop. Implement P0952R2 "A new specification for std::generate_canonical". It has us start over if the naive generation of a float in 0..1 comes up exactly equal to 1, which occurs too rarely for the change to measurably affect performance. A test for the case already appears in 64351.cc. This change amounts to a different resolution for PR64351 and LWG 2524. libstdc++-v3/ChangeLog: PR libstdc++/119739 * include/bits/random.tcc --- libstdc++-v3/include/bits/random.tcc | 40 +++++++++++----------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc index 53ccacb2e38..e2c90e52c48 100644 --- a/libstdc++-v3/include/bits/random.tcc +++ b/libstdc++-v3/include/bits/random.tcc @@ -3355,38 +3355,28 @@ namespace __detail generate_canonical(_UniformRandomNumberGenerator& __urng) { static_assert(std::is_floating_point<_RealType>::value, - "template argument must be a floating point type"); + "template argument must be a floating point type"); - const size_t __b - = std::min(static_cast<size_t>(std::numeric_limits<_RealType>::digits), - __bits); - const long double __r = static_cast<long double>(__urng.max()) - - static_cast<long double>(__urng.min()) + 1.0L; + const size_t __b = std::min( + static_cast<size_t>(std::numeric_limits<_RealType>::digits), __bits); + const long double __r = + static_cast<long double>(__urng.max()) - + static_cast<long double>(__urng.min()) + 1.0L; const size_t __log2r = std::log(__r) / std::log(2.0L); - const size_t __m = std::max<size_t>(1UL, - (__b + __log2r - 1UL) / __log2r); + const size_t __m = std::max<size_t>(1UL, (__b + __log2r - 1UL) / __log2r); _RealType __ret; - _RealType __sum = _RealType(0); - _RealType __tmp = _RealType(1); - for (size_t __k = __m; __k != 0; --__k) + do { - __sum += _RealType(__urng() - __urng.min()) * __tmp; - __tmp *= __r; - } - __ret = __sum / __tmp; - if (__builtin_expect(__ret >= _RealType(1), 0)) - { -#if _GLIBCXX_USE_C99_MATH_FUNCS - __ret = std::nextafter(_RealType(1), _RealType(0)); -#else - __ret = _RealType(1) - - std::numeric_limits<_RealType>::epsilon() / _RealType(2); -#endif - } + _RealType __sum = _RealType(0); + _RealType __tmp = _RealType(1); + for (size_t __k = __m; __k != 0; --__k, __tmp *= __r) + __sum += _RealType(__urng() - __urng.min()) * __tmp; + __ret = __sum / __tmp; + } while (__builtin_expect(__ret >= _RealType(1), false)); return __ret; } _GLIBCXX_END_NAMESPACE_VERSION -} // namespace + } // namespace #endif -- 2.50.0