On Mon, 12 Jan 2026 at 10:25, Tomasz Kamiński <[email protected]> wrote:
>
> This updates test01, so it properly handle 128bit floating points,
> including situation when long double uses such representation.
> Firstly, the computation of skips is corrected, by discarding number
> number values equal to number of calls required to generate element
"discarding number number values" -> "discarding the number of values"
> (skips become zero for all non-float correctly). Furthermore, checks
> of histogram for types using iec559 representation, is moved inside
> test01 function, so we use correct value for long double, depending
> on number of digits in mantissa on given platform.
>
> We also extend test to cover __float128, to test 128bit floating
> point on more platforms.
>
> libstdc++-v3/ChangeLog:
>
> *
> testsuite/26_numerics/random/uniform_real_distribution/operators/gencanon.cc:
> Updated test.
> ---
> Tested the gencanon.cc file locally with all standard modes, and
> with/without -m32. OK for trunk?
>
> .../operators/gencanon.cc | 106 ++++++++++++------
> 1 file changed, 70 insertions(+), 36 deletions(-)
>
> 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 69a061071da..96f18b19c25 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
> @@ -8,6 +8,7 @@
> #include <cmath>
> #include <testsuite_hooks.h>
> #include <array>
> +#include <iostream>
>
> template <std::uint64_t max_val>
> struct local_rng : std::mt19937
> @@ -25,13 +26,25 @@ struct local_rng : std::mt19937
> // sixth iteration for float, and not at all for double.
> // However, each double iteration requires two calls to the RNG.
>
> +template<typename T>
> +int ifloor(T t)
> +{ return static_cast<int>(std::floor(t)); }
> +
> +#ifdef __SIZEOF_FLOAT128__
> +int ifloor(__float128 t)
> +{ return static_cast<int>(t); }
> +#endif
> +
> template <typename T, typename RNG>
> void
> -test01(RNG& rng, RNG& rng2,
> - int& deviation, int& max, int& rms, int& zero, int& skips)
> +test01(RNG& rng, RNG& rng2, int& skips)
> {
> + constexpr size_t mantisa = std::numeric_limits<T>::digits;
> + constexpr size_t call_per_elem = (mantisa + 31) / 32;
> +
> const auto size = 1000000, buckets = 100;
> std::array<int, buckets> histo{};
> + int zero = 0;
> for (auto i = 0; i != size; ++i) {
> T sample = std::generate_canonical<T, -1u>(rng);
> VERIFY(sample >= T(0.0));
> @@ -39,16 +52,20 @@ test01(RNG& rng, RNG& rng2,
> if (sample == T(0.0)) {
> ++zero;
> }
> - auto bucket = static_cast<int>(std::floor(sample * buckets));
> + auto bucket = ifloor(sample * buckets);
> ++histo[bucket];
> - rng2.discard(1);
> + rng2.discard(call_per_elem);
> if (rng != rng2) {
> ++skips;
> - rng2.discard(1);
> + rng2.discard(call_per_elem);
> VERIFY(rng == rng2);
> }
> }
> - int devsquare = 0;
> +
> + if (!std::numeric_limits<T>::is_iec559)
> + return;
> +
> + int deviation = 0, max = 0, rms = 0, devsquare = 0;
> for (int i = 0; i < buckets; ++i) {
> const auto expected = size / buckets;
> auto count = histo[i];
> @@ -59,6 +76,33 @@ test01(RNG& rng, RNG& rng2,
> if (diff > max) max = diff;
> }
> rms = std::sqrt(devsquare);
> +
> + switch (mantisa)
> + {
> + case 24: // iee32
iee32 -> ieee32
> + std::cout << deviation << std::endl;
This line and the #include <iostream> can be removed.
> + VERIFY(deviation == 7032);
> + VERIFY(max == 276);
> + VERIFY(rms == 906);
> + VERIFY(zero == 0);
> + break;
> + case 53: // iee64
iee64 -> ieee64
> + case 64: // iee80 9086
ieee
> + VERIFY(deviation == 7650);
> + VERIFY(max == 259);
> + VERIFY(rms == 975);
> + VERIFY(zero == 0);
> + break;
> + case 113: // iee128
ieee
> + VERIFY(deviation == 9086);
> + VERIFY(max == 290);
> + VERIFY(rms == 1142);
> + VERIFY(zero == 0);
> + break;
> + default:
> + VERIFY(false);
> + break;
> + }
> }
>
> // This one is for use with local_rng
> @@ -145,47 +189,37 @@ test00()
> rng.discard(12 * 629143);
>
> { // float
> - int deviation{}, max{}, rms{}, zero{}, skips{};
> + int skips{};
> auto rng2{rng};
> auto rng3{rng};
> - test01<float>(rng2, rng3, deviation, max, rms, zero, skips);
> -
> - if (std::numeric_limits<float>::is_iec559) {
> - VERIFY(deviation == 7032);
> - VERIFY(max == 276);
> - VERIFY(rms == 906);
> - VERIFY(zero == 0);
> - }
> + test01<float>(rng2, rng3, skips);
> VERIFY(skips == 1);
> }
> { // double
> - int deviation{}, max{}, rms{}, zero{}, skips{};
> + int skips{};
> auto rng2{rng};
> auto rng3{rng};
> - test01<double>(rng2, rng3, deviation, max, rms, zero, skips);
> -
> - if (std::numeric_limits<double>::is_iec559) {
> - VERIFY(deviation == 7650);
> - VERIFY(max == 259);
> - VERIFY(rms == 975);
> - VERIFY(zero == 0);
> - }
> - VERIFY(skips == 1000000);
> + test01<double>(rng2, rng3, skips);
> + VERIFY(skips == 0);
> }
> - { // long double, same answers as double
> - int deviation{}, max{}, rms{}, zero{}, skips{};
> + { // long double
> + int skips{};
> auto rng2{rng};
> auto rng3{rng};
> - test01<long double>(rng2, rng3, deviation, max, rms, zero, skips);
> -
> - if (std::numeric_limits<double>::is_iec559) {
> - VERIFY(deviation == 7650);
> - VERIFY(max == 259);
> - VERIFY(rms == 975);
> - VERIFY(zero == 0);
> - }
> - VERIFY(skips == 1000000);
> + test01<long double>(rng2, rng3, skips);
> + VERIFY(skips == 0);
> + }
> +#ifndef _GLIBCXX_GENERATE_CANONICAL_STRICT
> +# ifdef __SIZEOF_FLOAT128__
> + {
> + int skips{};
> + auto rng2{rng};
> + auto rng3{rng};
> + test01<__float128>(rng2, rng3, skips);
> + VERIFY(skips == 0);
> }
> +# endif
> +#endif
>
> { // local RNG, returns [0..999'999)
> int deviation{}, max{}, rms{}, zero{}, skips{};
> --
> 2.52.0
>