[PATCHv5] libstdc++: Add generate_canonical impl (P0952, LWG2524) [PR119739]
Nathan Myers
ncm@cantrip.org
Thu Aug 14 00:11:26 GMT 2025
Thank you.
On 8/13/25 03:38, Tomasz Kaminski wrote:
> On Wed, Aug 13, 2025 at 12:06 AM Nathan Myers <ncm@cantrip.org> wrote:
>> +#if __cplusplus < 202400 || defined(__clang__)
> I do not think that not implementing this issue for clang is really a good
> option.
> The function is small enough that you could test it on the compiler
> explorer,
> and you may use that to check how we behave for constant folding.
> I would instead replace the constexpr variable with `const` and see if with
> optimization GCC does constant fold calls to floor, pow etc.
> Of as alternative, define a helper macro like
> _GLIBCXX_GENCANONICAL_CONSTEXPR,
> (and undefine it at end of the file),\ that would be constexpr for gcc and
> empty for clang,
> and then define the variables as:
> _GLIBCXX_GENCANONICAL_CONSTEXPR
> const _RealT __Rk = __builtin_pow(__R, __k)
>
> This would allow us to make them constexpr if later version of clang
> supports that.
Unfortunately, making __Rk const does not suffice to allow use of
Clang's __builtin_pow. In v6 I have provided local versions of pow
and floor for use in the constexpr computations, when building
with Clang, that on Gcc forward to builtins. My consteval floor
for Clang propagates the argument through a ULL, making it less
general than the Gcc impl, though sufficient for long double,
but at runtime it uses the regular __builtin_floor.
> This is why I have also suggested adjusting the computation of __k, so we
> can use __builting_log to compute the value faster in most common case.
I don't understand how the performance difference at compile time
would justify the extra complexity, when we need the more general
code anyhow for when the radix != 2. In use, the loop runs only
one iteration, and only at compile time.
>> + constexpr _RealT __rd = __builtin_pow(_RealT(__r), __d);
>> + const unsigned __k = [](_RealT __R, _RealT __rd) consteval
>> + {
>> + unsigned __i = 1;
>> + for (auto __Ri = __R; __Ri < __rd; __Ri *= __R)
>> + ++__i;
>> + return __i;
>> + } (__R, __rd);
>> + constexpr _RealT __Rk = __builtin_pow(__R, __k);
>> + constexpr _RealT __x = __builtin_floor(__Rk / __rd);
>> + constexpr _RealT __xrd = __x * __rd;
>> +
>> + _RealT __sum;
>> + do
>> + {
>> + _RealT __Ri = _RealT(1);
>> + __sum = __sample(__urng());
>> + if constexpr (__k > 1)
>> + for (int __i = 1; __i != __k; ++__i)
>> + __Ri *= __R, __sum += __sample(__urng()) * __Ri;
>> + } while (__builtin_expect(__sum >= __xrd, false));
>> + _RealT __ret = __builtin_floor(__sum / __x) / __rd;
>> + return __ret;
>> + }
More information about the Libstdc++
mailing list