[PATCHv2] libstdc++: Adjust generate_canonical (P0952, LWG2524) [PR119739]

Nathan Myers ncm@cantrip.org
Thu Aug 7 05:38:15 GMT 2025


Changes in v2:
 * Re-initialize inner loop variables.
 * Compute result optimistically, check outcome reliably.

Changes:
 * Whitespace tweaks aside, this just strips out the existing fixup and
  wraps the generator in a do .. while loop.

Implement P0952R2 "A new specification for std::generate_canonical".
It has us start over if the naive generation of a float in 0..1
comes up exactly equal to 1, which occurs too rarely for the change
to measurably affect performance.

A test for the case already appears in 64351.cc. This change amounts
to a different resolution for PR64351 and LWG 2524.

libstdc++-v3/ChangeLog:
	PR libstdc++/119739
	* include/bits/random.tcc
---
 libstdc++-v3/include/bits/random.tcc | 40 +++++++++++-----------------
 1 file changed, 15 insertions(+), 25 deletions(-)

diff --git a/libstdc++-v3/include/bits/random.tcc b/libstdc++-v3/include/bits/random.tcc
index 53ccacb2e38..e2c90e52c48 100644
--- a/libstdc++-v3/include/bits/random.tcc
+++ b/libstdc++-v3/include/bits/random.tcc
@@ -3355,38 +3355,28 @@ namespace __detail
     generate_canonical(_UniformRandomNumberGenerator& __urng)
     {
       static_assert(std::is_floating_point<_RealType>::value,
-		    "template argument must be a floating point type");
+	"template argument must be a floating point type");
 
-      const size_t __b
-	= std::min(static_cast<size_t>(std::numeric_limits<_RealType>::digits),
-                   __bits);
-      const long double __r = static_cast<long double>(__urng.max())
-			    - static_cast<long double>(__urng.min()) + 1.0L;
+      const size_t __b = std::min(
+	static_cast<size_t>(std::numeric_limits<_RealType>::digits), __bits);
+      const long double __r =
+	static_cast<long double>(__urng.max()) -
+	static_cast<long double>(__urng.min()) + 1.0L;
       const size_t __log2r = std::log(__r) / std::log(2.0L);
-      const size_t __m = std::max<size_t>(1UL,
-					  (__b + __log2r - 1UL) / __log2r);
+      const size_t __m = std::max<size_t>(1UL, (__b + __log2r - 1UL) / __log2r);
       _RealType __ret;
-      _RealType __sum = _RealType(0);
-      _RealType __tmp = _RealType(1);
-      for (size_t __k = __m; __k != 0; --__k)
+      do
 	{
-	  __sum += _RealType(__urng() - __urng.min()) * __tmp;
-	  __tmp *= __r;
-	}
-      __ret = __sum / __tmp;
-      if (__builtin_expect(__ret >= _RealType(1), 0))
-	{
-#if _GLIBCXX_USE_C99_MATH_FUNCS
-	  __ret = std::nextafter(_RealType(1), _RealType(0));
-#else
-	  __ret = _RealType(1)
-	    - std::numeric_limits<_RealType>::epsilon() / _RealType(2);
-#endif
-	}
+	  _RealType __sum = _RealType(0);
+	  _RealType __tmp = _RealType(1);
+	  for (size_t __k = __m; __k != 0; --__k, __tmp *= __r)
+	    __sum += _RealType(__urng() - __urng.min()) * __tmp;
+	  __ret = __sum / __tmp;
+	} while (__builtin_expect(__ret >= _RealType(1), false));
       return __ret;
     }
 
 _GLIBCXX_END_NAMESPACE_VERSION
-} // namespace
+  } // namespace
 
 #endif
-- 
2.50.0



More information about the Libstdc++ mailing list