On Wed, 17 Dec 2025 at 09:30, Nathan Myers <[email protected]> wrote:
>
> On 12/17/25 3:10 AM, Jakub Jelinek wrote:
> > On Wed, Dec 17, 2025 at 07:55:01AM +0100, Jakub Jelinek wrote:
> >> Because we don't have unsigned _BitInt(128) in C++ right now, I'm afraid 
> >> you
> >> want some unsigned __int128 like class for #ifndef __SIZEOF_INT128__ which
> >> will handle all the operations you need on a pair of unsigned long long.
>
> I had thought "#if defined (SIZEOF_INT128__)" would gate any
> mention of __int128. Is it that this symbol is defined where
> C code may use that type, even though C++ code cannot?

No, it's that this static_assert fails for i686 (and other 32-bit targets):

      if constexpr (__d <= 32)
        return __generate_canonical_any<_RealT, uint64_t, __d>(__urng);
      else
        {
#if defined(__SIZEOF_INT128__)
          static_assert(__d <= 64,
        "irregular RNG with float precision >64 is not supported");
          return __extension__ __generate_canonical_any<
        _RealT, unsigned __int128, __d>(__urng);
#else
          static_assert(false, "irregular RNG with float precision"
         " >32 requires __int128 support");
#endif
        }



>
> > Though, I wonder if you really need unsigned __int128 type for 32-bit
> > hosts (if __generate_canonical_pow2/any are copied/edited for the
> > 128-bit cases.
> >
> > Without 128-bit integral type, I think you don't need to worry about
> > __log2_R > 64, because simply there is no such unsigned integral type to
> > hold it.
>
> Correct... But we still want it to work for the > 64 case, in
> cases where we do finally get a 128-bit integer type.
>
> > So
> >    constexpr _RealT __Rk = _RealT(_UInt(1) << (__log2_Rk - 1)) * 2.0;
> > can be done in that case even using unsigned long long type.
>
> Shifting uint64_t(1) left 64 places, as would occur for
> __d == 64 and _RealT=long double (with its 64-bit mantissa)
> is UB and ill-formed in constexpr context...
>
> > (Though I wonder if it shouldn't be _RealT(2.0) instead of 2.0).
>
> Maybe?
>
> > I'd hope that
> >        const _UInt __x = _UInt(1) << __log2_x;
> > and
> >            _UInt __sum = _UInt(__urng() - _Urbg::min());
> > can be still done in unsigned long long type as well for similar reasons.
>
> > Only the
> >            for (unsigned __i = __k - 1, __shift = 0; __i > 0; --__i)
> >              {
> >                __shift += __log2_R;
> >                __sum |= _UInt(__urng() - _Urbg::min()) << __shift;
> >              }
> >            const _RealT __ret = _RealT(__sum >> __log2_x) / __rd;
> > part is problematic, but can't that be handled by hand with a pair of
> > unsigned long long __sums?  Of course one can't convert to _RealT in
> > that case from the pair but needs to be done from the MS half, multiply
> > by some precomputed constant and add the LS half.
>
> Emulating 128-bit integer operations seems like heroics unless C++
> is not expected ever to get __int128. The intention was to support
> 128-bit floating-point formats, with mantissa >= 106 bits, in places
> where users have them. Does it seem likely a quad-precision floating
> point type would be implemented, but not __int128?
>

Reply via email to