C++ Logo

std-proposals

Advanced search

Re: [std-proposals] solution proposal for Issue 2524: generate_canonical can occasionally return 1.0

From: Juan Lucas Rey <juanlucasrey_at_[hidden]>
Date: Sat, 6 Dec 2025 16:53:11 +0000
Hi,

Thanks. the original proposition is basically to be able to have good
resolution on both tails. Currently we have good resolution only on
the left tail [0, epsilon], which benefits from subnormal numbers.
Subnormal numbers allow around 2^23 values for floats and 2^52 values
for doubles, that's a tremendous amount of resolution and it is
certainly useful for users doing simulations to study extreme events
(so, events on tails). I just think it's a shame to have that
resolution on the left tail and only a single value on the right tail.

The fact that this CAN help with the implementations of
std::exponential_distribution returning +inf (even though as specified
earlier, no indication is made by the standard on what tool to use) is
one of the potential benefits of having this distribution available.
It could benefit all distributions.

Lucas

On Sat, 6 Dec 2025 at 16:35, Lénárd Szolnoki <cpp_at_[hidden]> wrote:
>
>
>
> On 06/12/2025 08:16, Juan Lucas Rey wrote:
> > Hi,
> >
> > The whole point is that, when u is very close to 1,
> > -std::log(result_type(1) - u) * lambda_inv; would have returned
> > infinity because "result_type(1) - u" ends up being 0.
>
> Yes, but you effectively achieve that by having a good uniform distribution on (0, 1]. I
> agree that it is a much better fit for generating the exponential distribution, as you get
> your increased resolution near the singularity, without including the singularity.
>
> I don't see why you need a centered uniform distribution to generate a good uniform
> distribution on (0, 1], but maybe it's more versatile in general.>
> > by representing that difference by -u, that situation is avoided, so
> > there IS increased resolution. -u can be represented by subnormal
> > numbers, and std::log is able to give very good values for those
> > subnormal numbers.Yes, but that's equally true for generating a good uniform distribution on (0, 1], and use
> -log(u) for the whole range.
>
> I see that -log(1 - u) solution with u being uniform on [0, 1) has still quite a distorted
> tail distribution. This solution can't produce a result larger than 36.7f for floats for
> lambda=1. While the theoretical probability to produce larger results than this is small,
> it's not academically small.
>
> >
> > on your second comment: "makes the distribution less accurate near 0,
> > as it skips over a lot of representable values", could you develop
> > further?
>
> Scratch that, I made a mistake there.
>
> Lénárd
>
> >
> > Thanks,
> > Lucas
> >
> > On Sat, 6 Dec 2025 at 01:09, Lénárd Szolnoki <cpp_at_[hidden]> wrote:
> >>
> >>
> >>
> >> On 05/12/2025 22:32, Lénárd Szolnoki via Std-Proposals wrote:
> >>>
> >>>
> >>> On 04/12/2025 19:05, Juan Lucas Rey via Std-Proposals wrote:
> >>>> in the current proposal,
> >>>> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p0952r2.html
> >>>>
> >>>> it is mentioned "In particular, code that depends on a specific
> >>>> sequence of results from repeated invocations, or on a particular
> >>>> number of calls to the URBG argument, will be broken."
> >>>>
> >>>> This solution avoids breaking this.
> >>>
> >>> In the attached proposal within the implementation of exponential_distribution you have:
> >>>
> >>> const auto u
> >>> = std::generate_canonical_centered<
> >>> result_type,
> >>> std::numeric_limits<result_type>::digits
> >>> >(g);
> >>> if (std::copysign(1.0, u) > 0) {
> >>> return -std::log(result_type(1) - u) * lambda_inv;
> >>> } else {
> >>> return -std::log(-u) * lambda_inv;
> >>> }
> >>>
> >>> This is exactly equivalent to:
> >>>
> >>> const auto u = ...
> >>> const auto u2
> >>> = std::copysign(1.0, u) > 0
> >>> ? result_type(1) - u
> >>> : -u;
> >>> return -std::log(u2) * lambda_inv;
> >>>
> >>> Generating the centered uniform distribution seems redundant, you effectively map it to a
> >>> uniform distribution on [0, 1) anyway with u2. So this also boils down to fixing the
> >>> distribution on [0, 1), and centering doesn't give you anything for this particular use
> >>> case. You throw away your increased resolution at `result_type(1) - u`.
> >>
> >> Correction, for u2 you effectively generate uniformly on (0, 1]. This improves the tail
> >> distribution of the generated exponential_distribution compared to using
> >> generate_canonical, but makes the distribution less accurate near 0, as it skips over a
> >> lot of representable values.
> >>
> >> Honestly, neither technique is great in terms of accuracy, and it's probably possible to
> >> implement exponential_distribution in a way that it can actually take any representable
> >> value within the distribution. And the exponential distribution has density beyond
> >> FLT_MAX, so theoretically inf is a valid result, but the probability of rolling above
> >> FLT_MAX is usually beyond astronomically low, so I guess fixing that made sense.
> >>
> >>>
> >>>>
> >>>>
> >>>> --
> >>>> Std-Proposals mailing list
> >>>> Std-Proposals_at_[hidden]
> >>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> >>>
> >>>
> >>> --
> >>> Std-Proposals mailing list
> >>> Std-Proposals_at_[hidden]
> >>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
> >>
>

Received on 2025-12-06 16:53:24