https://gcc.gnu.org/g:9614fe95eb33f8ff783b899049f61f74373ff982
commit r16-6242-g9614fe95eb33f8ff783b899049f61f74373ff982 Author: Jonathan Wakely <[email protected]> Date: Wed Dec 17 18:36:36 2025 +0000 libstdc++: Fix up std::generate_canonical for 32-bit arches Make use of __detail::_Select_uint_least_t<d>::type for std::generate_canonical, so that we choose an appropriately sized integer based on the number of bits needed, and so we have a 128-bit integer type even on 32-bit targets (via the new __rand_uint128 class). libstdc++-v3/ChangeLog: * include/bits/random.tcc (__generate_canonical_pow2): Adjust comments. Remove _UInt template parameter and define it in the body using _Select_uint_least_t<__d>. Remove popcount call for getting the width of the _UInt type. Cast floating-point literal to _RealT. (__generate_canonical_any): Remove _UInt template parameter and define it in the body using _Select_uint_least_t<__d * 2>. Use direct-initialization for _UInt variables. Cast floating-point literal to _RealT. (generate_canonical): Remove unused typedef. Remove constexpr-if branches and remove unsigned type from template argument lists. Co-authored-by: Jakub Jelinek <[email protected]> Reviewed-by: Nathan Myers <[email protected]> Diff: --- libstdc++-v3/include/bits/random.tcc | 75 +++++++++++------------------------- 1 file changed, 23 insertions(+), 52 deletions(-) diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc index 68eae419b721..0256059ab72c 100644 --- a/libstdc++-v3/include/bits/random.tcc +++ b/libstdc++-v3/include/bits/random.tcc @@ -3482,13 +3482,13 @@ namespace __detail #pragma GCC diagnostic ignored "-Wc++14-extensions" // for variable templates #pragma GCC diagnostic ignored "-Wc++17-extensions" // if constexpr - // This version is used when Urbg::max()-Urbg::min() is a power of - // two less 1, the norm in real programs. It works by calling urng() - // as many times as needed to fill the target mantissa, accumulating - // entropy into an integer value, converting that to the float type, - // and then dividing by the range of the integer value (a constexpr - // power of 2, so only adjusts the exponent) to produce a result in - // [0..1]. In case of an exact 1.0 result, we re-try. + // __generate_canonical_pow2 is used when Urbg::max()-Urbg::min() is + // a power of two less 1. It works by calling urng() as many times as + // needed to fill the target mantissa, accumulating entropy into an + // integer value, converting that to the float type, and then dividing + // by the range of the integer value (a constexpr power of 2, + // so only adjusts the exponent) to produce a result in [0..1]. + // In case of an exact 1.0 result, we re-try. // // It needs to work even when the integer type used is only as big // as the float mantissa, such as uint64_t for long double. So, @@ -3512,20 +3512,21 @@ namespace __detail // This implementation works with std::bfloat16, which can exactly // represent 2^32, but not with std::float16_t, limited to 2^15. - template<typename _RealT, typename _UInt, size_t __d, typename _Urbg> + template<typename _RealT, size_t __d, typename _Urbg> _RealT __generate_canonical_pow2(_Urbg& __urng) { + using _UInt = typename __detail::_Select_uint_least_t<__d>::type; + // Parameter __d is the actual target number of bits. // Commented-out assignments below are of values specified in // the Standard, but not used here for reasons noted. // r = 2; // Redundant, we only support radix 2. using _Rng = decltype(_Urbg::max()); const _Rng __rng_range_less_1 = _Urbg::max() - _Urbg::min(); - const _UInt __uint_range_less_1 = ~_UInt(0); // R = _UInt(__rng_range_less_1) + 1; // May wrap to 0. const auto __log2_R = __builtin_popcountg(__rng_range_less_1); - const auto __log2_uint_max = __builtin_popcountg(__uint_range_less_1); + const auto __log2_uint_max = sizeof(_UInt) * __CHAR_BIT__; // rd = _UInt(1) << __d; // Could overflow, UB. const unsigned __k = (__d + __log2_R - 1) / __log2_R; const unsigned __log2_Rk_max = __k * __log2_R; @@ -3533,7 +3534,7 @@ namespace __detail __log2_uint_max < __log2_Rk_max ? __log2_uint_max : __log2_Rk_max; static_assert(__log2_Rk >= __d); // Rk = _UInt(1) << __log2_Rk; // Likely overflows, UB. - constexpr _RealT __Rk = _RealT(_UInt(1) << (__log2_Rk - 1)) * 2.0; + constexpr _RealT __Rk = _RealT(_UInt(1) << (__log2_Rk - 1)) * _RealT(2.0); #if defined(_GLIBCXX_GENERATE_CANONICAL_STRICT) const unsigned __log2_x = __log2_Rk - __d; // # of spare entropy bits. #else @@ -3582,29 +3583,31 @@ namespace __detail // (the range of values produced by the rng) up to twice the length // of the mantissa. - template<typename _RealT, typename _UInt, size_t __d, typename _Urbg> + template<typename _RealT, size_t __d, typename _Urbg> _RealT __generate_canonical_any(_Urbg& __urng) { - static_assert(__d < __builtin_popcountg(~_UInt(0))); + using _UInt = typename __detail::_Select_uint_least_t<__d * 2>::type; + // Names below are chosen to match the description in the Standard. // Parameter d is the actual target number of bits. - const _UInt __r = 2; + const _UInt __r{2}; const _UInt __R = _UInt(_Urbg::max() - _Urbg::min()) + 1; const _UInt __rd = _UInt(1) << __d; const unsigned __k = __gen_can_rng_calls_needed(__R, __rd); const _UInt __Rk = __gen_can_pow(__R, __k); - const _UInt __x = __Rk/__rd; + const _UInt __x = __Rk / __rd; while (true) { - _UInt __Ri = 1, __sum = __urng() - _Urbg::min(); + _UInt __Ri{1}; + _UInt __sum{__urng() - _Urbg::min()}; for (int __i = __k - 1; __i > 0; --__i) { __Ri *= __R; - __sum += (__urng() - _Urbg::min()) * __Ri; + __sum += _UInt{__urng() - _Urbg::min()} * __Ri; } - const _RealT __ret = _RealT(__sum / __x) / __rd; + const _RealT __ret = _RealT(__sum / __x) / _RealT(__rd); if (__ret < _RealT(1.0)) return __ret; } @@ -3660,47 +3663,15 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2) "float16_t type is not supported, consider using bfloat16_t"); #endif - using _Rng = decltype(_Urbg::max()); const unsigned __d_max = std::numeric_limits<_RealT>::digits; const unsigned __d = __digits > __d_max ? __d_max : __digits; // If the RNG range is a power of 2 less 1, the float type mantissa // is enough bits. If not, we need more. if constexpr (__is_power_of_2_less_1(_Urbg::max() - _Urbg::min())) - { - if constexpr (__d <= 32) - return __generate_canonical_pow2<_RealT, uint32_t, __d>(__urng); - else if constexpr (__d <= 64) - return __generate_canonical_pow2<_RealT, uint64_t, __d>(__urng); - else - { -#if defined(__SIZEOF_INT128__) - // Accommodate double double or float128. - return __extension__ __generate_canonical_pow2< - _RealT, unsigned __int128, __d>(__urng); -#else - static_assert(false, - "float precision >64 requires __int128 support"); -#endif - } - } + return __generate_canonical_pow2<_RealT, __d>(__urng); else // Need up to 2x bits. - { - if constexpr (__d <= 32) - return __generate_canonical_any<_RealT, uint64_t, __d>(__urng); - else - { -#if defined(__SIZEOF_INT128__) - static_assert(__d <= 64, - "irregular RNG with float precision >64 is not supported"); - return __extension__ __generate_canonical_any< - _RealT, unsigned __int128, __d>(__urng); -#else - static_assert(false, "irregular RNG with float precision" - " >32 requires __int128 support"); -#endif - } - } + return __generate_canonical_any<_RealT, __d>(__urng); } _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
