On Mon, Jul 20, 2026 at 2:32 PM Jonathan Wakely <[email protected]> wrote:
> On Mon, 20 Jul 2026 at 13:02, Tomasz Kaminski <[email protected]> wrote: > > > > > > > > On Mon, Jul 20, 2026 at 1:45 PM Jonathan Wakely <[email protected]> > wrote: > >> > >> On Tue, 02 Jun 2026 at 16:01 +0200, Tomasz Kamiński wrote: > >> >This patch splits implementation of generate_cannonical_any, into tree > >> > >> "canonical" > >> "three" > >> > >> >different path depending on bits generated (R), required bits of > entropy > >> >(b), and value k such that R^k > 2^d > R^(k-1): > >> >* log2(R) >= d: single call of generator is sufficient (k = 1), > >> > and computation can be performed in the generator value type (_UIntR) > >> >* bit_width(R^k) <= 128: computation can be performed using type > >> > __detail::_Select_uint_least_t; previous implementation is reused > >> >* bit_width(R^k) > 128: the computations required may overflow 128 bit; > >> > such generators were previously unsupported, as illustrated by > >> > r17-507-g5d17eec7d83445 > >> > > >> >This patch implements the support for the last branch, by observing > >> >that while it is possible for computation to overflow 128 the sum: > >> > sum_[0, k) urng() * R^i > >> >The values of sum, such that (sum / x * 2^d) > 1, are rejected, and > >> >any value (sum / x) > 2^d can be rejected. As 2^d is guaranteed to fit > >> >in 128 integer, we can use above to reject the value, before overflow > >> >will occur. > >> > > >> >Firstly, we know that for l = k-1, the value R^l < 2^d, and > >> >sum_[0, l) urng() * R^i <= R^l (because urng() is alwayus < R), > >> > >> "always" > >> > >> >always fit in 128bit integer. We compute tha valuet (__lsum) using > >> > >> "value" > >> > >> >normal loop. > >> > > >> >This leaves us with final iteration of multiplying __kth * R^l, > >> >where __kth is result of invocation of urng. In that case we > >> >compute the bitwidth (__abits) of value that can be multiplied > >> >by _R^l without overflow 128bit integer. The __kth * R^l is > >> >performed by multiplying the loop of __abits of __kth in > >> >loop where: > >> >* __sumx (initially __lsum / __x) is the current value of sum / x > >> >* __remx (initially 2^d - __sumx) is the value that we can still > >> > add before overflowing (shifted with each iteration) > >> >* __modx (initially __modx % __x) are corrected reminders > >> >In each iteration the lowest __kth bits are multiplied with _Rl > (__val), > >> >scaled (__valx) and checked against __rem. When fits the __sumx, __modx > >> >and __remx are updated, and both values of __remx and __kth are shifted > >> >right by __abits. > >> > > >> >If the multiplication finished without overflow (__kth is zero), > >> > we handle the collected reminders (__modx), and compute the __ret > value. > >> > >> "remainders" (and there seems to be a stray space at the start of the > >> line) > >> > >> >The value greater or equal 1 (e.g. due floating point aproximation), > are > >> > >> "approximation" > >> > >> >still rejected. > >> > > >> >Similar approach is applied when computing x = R^k / 2^d. > >> >Again while R^k will overflow 128 bits, we know that x < R (so fits > >> >in 64bits), as R^l < 2^d < R^k, then x < R. We again compute > >> >R * R^l / 2^d, by splitting the value of R into __abits chunks (_pR). > >> >For result of chunks multipliations (_pRk), the bits (_xp) remaining > >> > >> "multiplications" > >> > >> >after division by __shift (starts from __d and reduces by __abits), > >> >are collected into cumulative value of __x. While the lower bits > >> >are preserved for later iteration (__pRk). > >> > > >> > PR libstdc++/119739 > >> > > >> >libstdc++-v3/ChangeLog: > >> > > >> > * include/bits/random.tcc (__generate_canonical_any): > >> > Rewrite to support more cases. > >> > * > testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc: > >> > Add test for previously unsupported generator. > >> > * > testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc: > >> > Add test for previously unsuported-generator ranges. > >> > * > testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng_neg.cc: > >> > Moved (now-supported) generator test to gencanon_eng.cc, and > removed > >> > the file. > >> >--- > >> >Tested on x86_64-linux. Also tested a modified version, with __bits <= > 128 > >> >branch being removed and __abits hardoced to 10. This confirms that new > >> >implementation gives the same output as existing one. > >> > > >> >OK for trunk? > >> > > >> > libstdc++-v3/include/bits/random.tcc | 169 +++++++++++++++--- > >> > .../operators/gencanon.cc | 96 ++++++++++ > >> > .../operators/gencanon_eng.cc | 63 +++++++ > >> > .../operators/gencanon_eng_neg.cc | 89 --------- > >> > 4 files changed, 300 insertions(+), 117 deletions(-) > >> > delete mode 100644 > libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng_neg.cc > >> > > >> >diff --git a/libstdc++-v3/include/bits/random.tcc > b/libstdc++-v3/include/bits/random.tcc > >> >index a8fab79961d..aa1f4a83a66 100644 > >> >--- a/libstdc++-v3/include/bits/random.tcc > >> >+++ b/libstdc++-v3/include/bits/random.tcc > >> >@@ -242,7 +242,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > >> > constexpr size_t > >> > mersenne_twister_engine<_UIntType, __w, __n, __m, __r, __a, __u, > __d, > >> > __s, __b, __t, __c, __l, __f>::tempering_u; > >> >- > >> >+ > >> > template<typename _UIntType, > >> > size_t __w, size_t __n, size_t __m, size_t __r, > >> > _UIntType __a, size_t __u, _UIntType __d, size_t __s, > >> >@@ -3753,38 +3753,151 @@ namespace __detail > >> > constexpr unsigned __log2R > >> > = sizeof(_UIntR) * __CHAR_BIT__ - __builtin_clzg(__R) - 1; > >> > // We overstimate number of required bits, by computing > >> >- // r such that l * log2(R) >= d, so: > >> >- // R^l >= (2 ^ log2(R)) ^ l == 2 ^ (log2(r) * l) >= 2^d > >> >- // And then requiring l * bit_width(R) bits. > >> >- constexpr unsigned __l = (__d + __log2R - 1) / __log2R; > >> >- constexpr unsigned __bits = (__log2R + 1) * __l; > >> >- using _UInt = typename > __detail::_Select_uint_least_t<__bits>::type; > >> >- > >> >- _GLIBCXX_GEN_CANON_CONST _UInt __rd = _UInt(1) << __d; > >> >- _GLIBCXX_GEN_CANON_CONST auto __logRrd = __gen_canon_log(__rd, > __R); > >> >- _GLIBCXX_GEN_CANON_CONST unsigned __k > >> >- = __logRrd.__floor_log + (__rd > __logRrd.__floor_pow); > >> >- > >> >- _GLIBCXX_GEN_CANON_CONST _UInt __Rk > >> >- = (__k > __logRrd.__floor_log) > >> >- ? _UInt(__logRrd.__floor_pow) * _UInt(__R) > >> >- : _UInt(__logRrd.__floor_pow); > >> >- _GLIBCXX_GEN_CANON_CONST _UInt __x = __Rk / __rd; > >> >+ // r such that m * log2(R) >= d, so: > >> >+ // R^m >= (2 ^ log2(R)) ^ m == 2 ^ (log2(r) * m) >= 2^d > >> >+ // And then requiring m * bit_width(R) bits. > >> >+ constexpr unsigned __m = (__d + __log2R - 1) / __log2R; > >> >+ constexpr unsigned __bits = (__log2R + 1) * __m; > >> >+ if constexpr (__log2R >= __d) > >> >+ { > >> >+ // range already provide required number of bits, > >> >+ // so in this case __k == 1, and single call to generator > >> >+ // is sufficient. Futhermore 2^d fits in _UIntR > >> >+ constexpr _UIntR __rd = _UIntR(1) << __d; > >> >+ constexpr _UIntR __x = __R >> __d; > >> > > >> >- while (true) > >> >+ while (true) > >> >+ { > >> >+ _UIntR __val(__urng() - _Urbg::min()); > >> >+ const _RealT __ret = _RealT(__val / __x) / _RealT(__rd); > >> >+ if (__ret < _RealT(1.0)) > >> >+ return __ret; > >> >+ } > >> >+ } > >> >+ // generator call produce less bits than __d, but R^k > rd fits > >> > >> s/less/fewer/ > >> > >> >+ // into 128 bits. > >> >+ else if constexpr (__bits <= 128) > >> > { > >> >- _UInt __Ri{1}; > >> >- _UInt __sum(__urng() - _Urbg::min()); > >> >- for (int __i = __k - 1; __i > 0; --__i) > >> >+ using _UInt = typename > __detail::_Select_uint_least_t<__bits>::type; > >> >+ > >> >+ _GLIBCXX_GEN_CANON_CONST _UInt __rd = _UInt(1) << __d; > >> >+ _GLIBCXX_GEN_CANON_CONST auto __logRrd = > __gen_canon_log(__rd, __R); > >> >+ // __rd is power of two, and __R is not so __floor_pow is > never > >> >+ // equal to __rd. > >> >+ _GLIBCXX_GEN_CANON_CONST unsigned __k = __logRrd.__floor_log > + 1; > >> >+ _GLIBCXX_GEN_CANON_CONST _UInt __Rk = __logRrd.__floor_pow * > _UInt(__R); > >> >+ // x = floor(R^k / 2^d) = R^k >> d; > >> >+ _GLIBCXX_GEN_CANON_CONST _UInt __x = __Rk >> __d; > >> >+ > >> >+ while (true) > >> > { > >> >- __Ri *= _UInt(__R); > >> >- __sum += _UInt(__urng() - _Urbg::min()) * __Ri; > >> >+ _UInt __Ri{1}; > >> >+ _UInt __sum(__urng() - _Urbg::min()); > >> >+ for (int __i = __k - 1; __i > 0; --__i) > >> >+ { > >> >+ __Ri *= __R; > >> >+ __sum += __Ri * _UIntR(__urng() - _Urbg::min()); > >> >+ } > >> >+ const _RealT __ret = _RealT(__sum / __x) / _RealT(__rd); > >> >+ if (__ret < _RealT(1.0)) > >> >+ return __ret; > >> > } > >> >- const _RealT __ret = _RealT(__sum / __x) / _RealT(__rd); > >> >- if (__ret < _RealT(1.0)) > >> >- return __ret; > >> > } > >> >-#undef _GLIBCXX_GEN_CANON_CONST > >> >+ else > >> >+ { > >> >+#pragma GCC diagnostic ignored "-Wshift-count-overflow" // we shift > by 64bits > >> > >> There's no push/pop around this pragma, but why is it here at all? > > > > We are inside push/pop for if constexpr, so I didn't think I needed to > add a new set. > > Ah yes, I looked at the wrong place. That's right then, but I'd like a > better comment on the pragma to say what it's for. If it's a false > positive due to a compiler bug, say that. > > > > > >> > >> Doesn't this warning indicate undefined behaviour, so we don't want to > >> just suppress it? > > > > As far as I recall, I thought this is UB caused by compiler, but that > was 6 months ago, > > Let me double check to be certain. > >> > >> > >> >+ static_assert(__log2R < 64, "Only generators emitting > up to 64 bits are supported"); > >> >+ using _UInt = typename > __detail::_Select_uint_least_t<128>::type; > >> >+ using _UInt64 = typename > __detail::_Select_uint_least_t<64>::type; > >> >+ > >> >+ _GLIBCXX_GEN_CANON_CONST _UInt __rd = _UInt(1) << __d; > >> >+ _GLIBCXX_GEN_CANON_CONST auto __logRrd = > __gen_canon_log(__rd, __R); > >> >+ // __rd is power of two, and __R is not so __floor_pow is > never > >> >+ // equal to __rd, and l == k - 1 > >> >+ _GLIBCXX_GEN_CANON_CONST unsigned __l = __logRrd.__floor_log; > >> >+ _GLIBCXX_GEN_CANON_CONST _UInt __Rl = __logRrd.__floor_pow; > >> >+ > >> >+ // __abits is maximum bit width of the value, that can > >> >+ // be multiplied by R^l without overflowing 128 bit integer > >> >+ // TODO: use bit_width(_Rl) > >> >+ _GLIBCXX_GEN_CANON_CONST unsigned __bwRl = (__log2R + 1) * > __l; > >> >+ // For __R close to power of two, the actual __k may be > smaller than __m, > >> >+ // and will use less than 128bits. > >> >+ _GLIBCXX_GEN_CANON_CONST unsigned __abits = __bwRl > 64 ? 128 > - __bwRl : 64; > We actually shift by 64 bits, per this comment, so that was real UB. I am changing this in next revision to: __bwRl > 96 ? 128 - __bwRl : 32, so we will do multiplication of chunks of 32bits or smaller. > >> >+ _GLIBCXX_GEN_CANON_CONST _UInt64 __amask > >> >+ = (__abits == 64) ? ~_UInt64(0) : (_UInt64(1) << __abits) > - 1; > >> >+ > >> >+ // Compute __x = _Rk / __rd (_Rk >> __d), by spliting _R into > chunks > >> >+ // (_pR) of __abits, so their multiplication does not > overflow 128 bits. > >> >+ // __x fits in 64bits, becuse __R^l < __rd < __R^k, thus __x > < _R > >> >+ _UInt64 __x(0), __pR(__R); _UInt __pRk(0); > >> >+ for (unsigned __shift = __d; __pR; __shift -= __abits) > >> >+ { > >> >+ __pRk += __Rl * (__pR & __amask); > >> >+ __pR >>= __abits; > >> >+ > >> >+ _UInt __xp(__pRk >> __shift); > >> >+ __x += _UInt64(__xp); > >> >+ __pRk -= (__xp << __shift); > >> >+ __pRk >>= __abits; > >> >+ } > >> >+ > >> >+ while (true) > >> >+ { > >> >+ // Compute sum of __urng() * R^i for i in range [0, l). > >> >+ // The values is smaller than R^l which is smaller than > >> > >> "value" > >> > >> >+ // __rd so fits into 128 bit integer. > >> >+ _UInt __Ri{1}; > >> >+ _UInt __lsum(__urng() - _Urbg::min()); > >> >+ for (int __i = __l - 1; __i > 0; --__i) > >> >+ { > >> >+ __Ri *= _UInt64(__R); > >> >+ __lsum += __Ri * _UInt64(__urng() - _Urbg::min()); > >> >+ } > >> >+ > >> >+ // The last iteration __urng() * R^k may overflow 128bit > >> >+ // integer. We use the fact that we reject __sum / __x >= > __rd, > >> >+ // and split __urng() value into chunks of __abits, so > their > >> >+ // products with R^l does not overflow 128bit. These > product > >> > >> "products" > >> > >> >+ // are then multiplied by 2^__shift, scaled by __x and > added into > >> >+ // the __sumx, until they value is smaller than remaining > value > >> > >> "the value" or "their value"? > >> > >> >+ // __rem [(__rd - __sumx) * 2^__shift], or whole value was > >> >+ // multiplied (__kth is zero). The reminder of division by > >> > >> "remainder" > >> > >> >+ // __x are accumulated into __modx value, and handled > later. > >> >+ // In consequence this guarantees that __sumx never > exceeded > >> > >> "exceeds" > >> > >> >+ // __rd value, and thus does not overflow 128 bit integer. > >> >+ _UInt __sumx = __lsum / __x, __modx = __lsum % __x; > >> >+ _UInt __remx = __rd - __sumx; > >> >+ _UInt64 __kth(__urng() - _Urbg::min()); > >> >+ for (unsigned __shift = 0; __kth; __shift += __abits) > >> >+ { > >> >+ const _UInt __val = __Rl * (__kth & __amask); > >> >+ const _UInt __valx = __val / __x; > >> >+ if (__valx > __remx) > >> >+ break; > >> >+ __kth >>= __abits; > >> >+ > >> >+ __sumx += (__valx << __shift); > >> >+ __modx += ((__val % __x) << __shift); > >> >+ > >> >+ __remx -= __valx; > >> >+ __remx >>= __abits; > >> >+ } > >> >+ if (__kth) // __sum / __x > _rd after adding __kth > iteration > >> >+ continue; > >> >+ > >> >+ // Handle accumulated reminders > >> > >> "remainders" > >> > >> >+ const _UInt __valx = __modx / __x; > >> >+ if (__valx > __rd - __sumx) // avoids overflow > >> >+ continue; > >> >+ > >> >+ __sumx += __valx; > >> >+ const _RealT __ret = _RealT(__sumx) / _RealT(__rd); > >> >+ if (__ret < _RealT(1.0)) > >> >+ return __ret; > >> >+ } > >> >+ } > >> >+#undef _GLIBCXX_GEN_CANON_CONST > >> > } > >> > > >> > #if !defined(_GLIBCXX_GENERATE_CANONICAL_STRICT) > >> >diff --git > a/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc > b/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc > >> >index ae93ec13b7a..4da53e9d4f2 100644 > >> >--- > a/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc > >> >+++ > b/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc > >> >@@ -234,6 +234,98 @@ test_2p31m1(const std::mt19937& rng) > >> > } > >> > } > >> > > >> >+template<std::uint64_t Max, typename Under = std::mt19937_64> > >> >+struct trimmed_engine > >> >+{ > >> >+ using result_type = std::uint64_t; > >> >+ > >> >+ static constexpr > >> >+ result_type min() > >> >+ { return result_type(0); } > >> >+ > >> >+ static constexpr > >> >+ result_type max() > >> >+ { return result_type(Max); } > >> >+ > >> >+ trimmed_engine() : dist(min(), max()) > >> >+ {} > >> >+ > >> >+ trimmed_engine(const Under& gen) > >> >+ : under(gen), dist(min(), max()) > >> >+ {} > >> >+ > >> >+ result_type operator()() > >> >+ { return dist(under); } > >> >+ > >> >+ void discard(std::size_t n) > >> >+ { > >> >+ for (size_t i = 0; i < n; ++i) > >> >+ (void)dist(under); > >> >+ } > >> >+ > >> >+ friend bool > >> >+ operator==(const trimmed_engine& lhs, const trimmed_engine& rhs) > >> >+ { return lhs.under == rhs.under; } > >> >+ > >> >+private: > >> >+ Under under; > >> >+ std::uniform_int_distribution<result_type> dist; > >> >+}; > >> >+ > >> >+// Uses a generate that emits range of size 2^55+2. > >> > >> "generator" > >> > >> >+// To produce 128bit IEE float, we need 3 calls to above generator, > that can > >> >+// produce value that have 155 bits, and uses separate path. > >> >+template <typename T> > >> >+void > >> >+test_2p55p1(const std::mt19937& rng) > >> >+{ > >> >+ if (!std::numeric_limits<T>::is_iec559) > >> >+ return; > >> >+ > >> >+ constexpr size_t mantissa = std::numeric_limits<T>::digits; > >> >+ constexpr size_t call_per_elem = (mantissa / 55) + 1; > >> >+ const trimmed_engine<(1ULL << 55) + 1ULL, std::mt19937> lrng{rng}; > >> >+ > >> >+ int deviation = 0, max = 0, rms = 0, zeros = 0; > >> >+ int skips = run_generator<T, -1u, call_per_elem, 1u> > >> >+ (lrng, deviation, max, rms, zeros); > >> >+ > >> >+ switch (mantissa) > >> >+ { > >> >+ case 24: // ieee32 > >> >+ VERIFY(skips == 0); > >> >+ VERIFY(deviation == 7682); > >> >+ VERIFY(max == 295); > >> >+ VERIFY(rms == 971); > >> >+ VERIFY(zeros == 0); > >> >+ break; > >> >+ case 53: // ieee64 > >> >+ VERIFY(skips == 0); > >> >+ VERIFY(deviation == 7682); > >> >+ VERIFY(max == 295); > >> >+ VERIFY(rms == 971); > >> >+ VERIFY(zeros == 0); > >> >+ break; > >> >+ case 64: // ieee80 > >> >+ VERIFY(skips == 0); > >> >+ VERIFY(deviation == 6788); > >> >+ VERIFY(max == 248); > >> >+ VERIFY(rms == 854); > >> >+ VERIFY(zeros == 0); > >> >+ break; > >> >+ case 113: // ieee128 > >> >+ VERIFY(skips == 0); > >> >+ VERIFY(deviation == 8222); > >> >+ VERIFY(max == 257); > >> >+ VERIFY(rms == 999); > >> >+ VERIFY(zeros == 0); > >> >+ break; > >> >+ default: > >> >+ VERIFY(false); > >> >+ break; > >> >+ } > >> >+} > >> >+ > >> > int main() > >> > { > >> > std::mt19937 rng(8890); > >> >@@ -244,20 +336,24 @@ int main() > >> > test_2p32<float>(rng); > >> > test_10p6<float>(rng); > >> > test_2p31m1<float>(rng); > >> >+ test_2p55p1<float>(rng); > >> > > >> > test_2p32<double>(rng); > >> > test_10p6<double>(rng); > >> > test_2p31m1<double>(rng); > >> >+ test_2p55p1<double>(rng); > >> > > >> > test_2p32<long double>(rng); > >> > test_10p6<long double>(rng); > >> > test_2p31m1<long double>(rng); > >> >+ test_2p55p1<long double>(rng); > >> > > >> > #ifndef _GLIBCXX_GENERATE_CANONICAL_STRICT > >> > # ifdef __SIZEOF_FLOAT128__ > >> > test_2p32<__float128>(rng); > >> > test_10p6<__float128>(rng); > >> > test_2p31m1<__float128>(rng); > >> >+ test_2p55p1<__float128>(rng); > >> > # endif > >> > #endif > >> > } > >> >diff --git > a/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc > b/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc > >> >index 662e3568a30..f586ebc7d17 100644 > >> >--- > a/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc > >> >+++ > b/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng.cc > >> >@@ -10,6 +10,40 @@ test_engine() > >> > (void)std::generate_canonical<_Real, size_t(-1)>(__engine); > >> > } > >> > > >> >+template<std::uint64_t Max, typename Under = std::mt19937_64> > >> >+struct trimmed_engine > >> >+{ > >> >+ using result_type = std::uint64_t; > >> >+ > >> >+ static constexpr > >> >+ result_type min() > >> >+ { return result_type(0); } > >> >+ > >> >+ static constexpr > >> >+ result_type max() > >> >+ { return result_type(Max); } > >> >+ > >> >+ trimmed_engine() : dist(min(), max()) > >> >+ {} > >> >+ > >> >+ result_type operator()() > >> >+ { return dist(under); } > >> >+ > >> >+private: > >> >+ Under under; > >> >+ std::uniform_int_distribution<result_type> dist; > >> >+}; > >> >+ > >> >+template<typename Real, size_t Bits> > >> >+void > >> >+test_bits() > >> >+{ > >> >+ trimmed_engine<(std::uint64_t(1) << Bits) - 1> pow2_engine; > >> >+ (void)std::generate_canonical<Real, -1u>(pow2_engine); > >> >+ trimmed_engine<(std::uint64_t(1) << Bits) - 2> non_pow2_engine; > >> >+ (void)std::generate_canonical<Real, -1u>(non_pow2_engine); > >> >+} > >> >+ > >> > template<typename _Real> > >> > void > >> > test_all_engines() > >> >@@ -29,6 +63,35 @@ test_all_engines() > >> > test_engine<_Real, std::philox4x32>(); > >> > test_engine<_Real, std::philox4x64>(); > >> > #endif > >> >+ > >> >+ // For 128bit floating points, generator emitting a range, which > size is > >> >+ // not power of two, but of width of B bits, such that for any N: > >> >+ // N * B < 113 (bits in ieee128) > >> >+ // (N+1) * B > 128 > >> >+ // use >128bits patch, as they would otherwise require integer with > more > >> >+ // than 128 bits. > >> >+ // N == 3: B in [43, 57) > >> >+ test_bits<_Real, 42>(); // 3 calls > >> >+ test_bits<_Real, 43>(); // 3 calls, >128bits path > >> >+ test_bits<_Real, 56>(); // 3 calls, >128bits path > >> >+ test_bits<_Real, 57>(); // 2 calls > >> >+ > >> >+ // N == 4: B in [33, 38) > >> >+ test_bits<_Real, 32>(); // 4 calls > >> >+ test_bits<_Real, 33>(); // 4 calls, >128bits path > >> >+ test_bits<_Real, 37>(); // 4 calls, >128bits path > >> >+ test_bits<_Real, 38>(); // 3 calls > >> >+ > >> >+ // N == 5: B in [26, 29) > >> >+ test_bits<_Real, 25>(); // 5 calls > >> >+ test_bits<_Real, 26>(); // 5 calls, >128bits path > >> >+ test_bits<_Real, 28>(); // 5 calls, >128bits path > >> >+ test_bits<_Real, 29>(); // 4 calls > >> >+ > >> >+ // N == 6: B == 22 > >> >+ test_bits<_Real, 21>(); // 6 calls > >> >+ test_bits<_Real, 22>(); // 6 calls, >128bits path > >> >+ test_bits<_Real, 23>(); // 5 calls > >> > } > >> > > >> > int main() > >> >diff --git > a/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng_neg.cc > b/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng_neg.cc > >> >deleted file mode 100644 > >> >index e3b4540bf2b..00000000000 > >> >--- > a/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng_neg.cc > >> >+++ /dev/null > >> >@@ -1,89 +0,0 @@ > >> >-// { dg-do compile { target { c++11 } } } > >> >-// { dg-require-effective-target __float128 } > >> >-// { dg-require-effective-target base_quadfloat_support } > >> >-// { dg-add-options __float128 } > >> >- > >> >-#include <random> > >> >-#include <cstdint> > >> >- > >> >-template<std::uint64_t Max, typename Under = std::mt19937_64> > >> >-struct trimmed_engine > >> >-{ > >> >- using result_type = std::uint64_t; > >> >- > >> >- static constexpr > >> >- result_type min() > >> >- { return result_type(0); } > >> >- > >> >- static constexpr > >> >- result_type max() > >> >- { return result_type(Max); } > >> >- > >> >- trimmed_engine() : dist(min(), max()) > >> >- {} > >> >- > >> >- result_type operator()() > >> >- { return dist(under); } > >> >- > >> >-private: > >> >- Under under; > >> >- std::uniform_int_distribution<result_type> dist; > >> >-}; > >> >- > >> >-template<typename Real, size_t Bits> > >> >-void > >> >-test_non_pow2() > >> >-{ > >> >- trimmed_engine<(std::uint64_t(1) << Bits) - 2> non_pow2_engine; > >> >- (void)std::generate_canonical<Real, -1u>(non_pow2_engine); > >> >-} > >> >- > >> >-template<typename Real, size_t Bits> > >> >-void > >> >-test_pow2() > >> >-{ > >> >- trimmed_engine<(std::uint64_t(1) << Bits) - 1> pow2_engine; > >> >- (void)std::generate_canonical<Real, -1u>(pow2_engine); > >> >-} > >> >- > >> >-int main() > >> >-{ > >> >- // For 128bit floating points, generator emitting a range, which > size is > >> >- // not power of two, but of width of B bits, such that for any N: > >> >- // N * B < 113 (bits in ieee128) > >> >- // (N+1) * B > 128 > >> >- // are not supported, as they would require integer with more than > 127 bits. > >> >- > >> >- // N == 3: B in [43, 57) > >> >- test_non_pow2<__float128, 42>(); // 3 calls > >> >- test_non_pow2<__float128, 43>(); // { dg-error "from here" } > >> >- test_non_pow2<__float128, 56>(); // { dg-error "from here" } > >> >- test_non_pow2<__float128, 57>(); // 2 calls > >> >- test_pow2<__float128, 43>(); > >> >- test_pow2<__float128, 56>(); > >> >- > >> >- // N == 4: B in [33, 38) > >> >- test_non_pow2<__float128, 32>(); // 4 calls > >> >- test_non_pow2<__float128, 33>(); // { dg-error "from here" } > >> >- test_non_pow2<__float128, 37>(); // { dg-error "from here" } > >> >- test_non_pow2<__float128, 38>(); // 3 calls > >> >- test_pow2<__float128, 33>(); > >> >- test_pow2<__float128, 37>(); > >> >- > >> >- // N == 5: B in [26, 29) > >> >- test_non_pow2<__float128, 25>(); // 5 calls > >> >- test_non_pow2<__float128, 26>(); // { dg-error "from here" } > >> >- test_non_pow2<__float128, 28>(); // { dg-error "from here" } > >> >- test_non_pow2<__float128, 29>(); // 4 calls > >> >- test_pow2<__float128, 26>(); > >> >- test_pow2<__float128, 28>(); > >> >- > >> >- // N == 6: B == 22 > >> >- test_non_pow2<__float128, 21>(); // 6 calls > >> >- test_non_pow2<__float128, 22>(); // { dg-error "from here" } > >> >- test_non_pow2<__float128, 23>(); // 5 calls > >> >- test_pow2<__float128, 22>(); > >> >-} > >> >- > >> >-// { dg-prune-output "no type named 'type' in 'struct > std::__detail::_Select_uint_least_t" } > >> >-// { dg-prune-output "static assertion failed: sorry, would be too > much trouble for a slow result" } > >> >-- > >> >2.54.0 > >> > > >> > > >> > >
