On Tue, 13 Jan 2026 at 09:40, Tomasz Kamiński <[email protected]> wrote:
>
> This patch add test illustrating, that after implementing P0952 "A new
> specification for
> std::generate_canonical", generators, that emit range of non-power-of-two
> size, that
> span over B bits, are not supported in combination with 128bits integer are
> not
> support for B in ranges: [22, 23), [26, 29), [33, 38), [43, 57). This is
> because, the
> lowest multiply of B that is larger of equal than 113 (size of mantisa of
> float128)
> is greater than 128, and thus they will require 256 bits integers support.
>
> This does not impact any generate defined in standard (see gencanon_eng.cc
> tests),
> nor generate emitting power of 2 sized ranges.
>
> PR libstdc++/119739
>
> libstdc++-v3/ChangeLog:
>
> *
> testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng_neg.cc:
> New test.
> ---
> I was planing to add the test before christmas break, but didn't managed to.
> I have some ideas, how to handle it, without requiring 128bit integers,
> but not sure how important this is. The failures will seem to be very arbitral
> form user-perspective, but custom engines are I assume uncommon.
>
> Tested new test on x86_64-linux locally with all supported standard modes,
> and with/without -m32. OK for trunk?
OK given Nathan's review.
>
>
> .../operators/gencanon_eng_neg.cc | 89 +++++++++++++++++++
> 1 file changed, 89 insertions(+)
> create mode 100644
> libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng_neg.cc
>
> 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
> new file mode 100644
> index 00000000000..42a4bc65d22
> --- /dev/null
> +++
> b/libstdc++-v3/testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon_eng_neg.cc
> @@ -0,0 +1,89 @@
> +// { dg-do compile { target { c++11 } } }
> +
> +#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.
> +#ifndef _GLIBCXX_GENERATE_CANONICAL_STRICT
> +# ifdef __SIZEOF_FLOAT128__
> + // 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>(); // 4 calls
> + test_pow2<__float128, 22>();
> +# endif
> +#endif
> +}
> +
> +// { 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.52.0
>