<div dir="auto"><div><br><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, 28 Aug 2026, 07:02 Tomasz Kamiński, <<a href="mailto:tkaminsk@redhat.com" target="_blank" rel="noreferrer">tkaminsk@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The commit r11-3757-g98c37d3bacbb2f that introduced Lemire's algorithm in<br>
uniform_int_distribution, assumed that any engine that generates range of<br>
size 2^32 or 2^64, returns a range starting from zero. While this is true<br>
for all standard providede engines, it may not be true for user provided<br>
ranges. In such case the produced output is no longer uniform:<br>
testDiscreteDist was failing for such engine.<br>
<br>
This patch simply substract __min (_Urbg::min()) from the generated number<br>
(__g()). As this value is compile time constant, this has no performance<br>
impact for generators producing ranges starting from zero.<br>
<br>
        PR libstdc++/118665<br>
<br>
libstdc++-v3/ChangeLog:<br>
<br>
        * include/bits/uniform_int_dist.h (uniform_int_distribution::_S_nd):<br>
        Substract __min (_Urbg::min()) from each generator invocation.<br>
        * testsuite/26_numerics/random/uniform_int_distribution/operators/values.cc:<br>
        Add testDiscreteDist for shifted (with non-zero min()) engine.<br>
<br>
Reviewed-by: Jonathan Wakely <<a href="mailto:jwakely@redhat.com" rel="noreferrer noreferrer" target="_blank">jwakely@redhat.com</a>><br>
Signed-off-by: Tomasz Kamiński <<a href="mailto:tkaminsk@redhat.com" rel="noreferrer noreferrer" target="_blank">tkaminsk@redhat.com</a>><br>
---<br>
v2 rebases this on top of the trunk, instead of hanging fix, so it is<br>
easier to backport.<br>
<br>
OK for trunk/16/15/14?<br></blockquote></div></div><div dir="auto"><br></div><div dir="auto">OK for all, thanks</div><div dir="auto"><br></div><div dir="auto"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
 libstdc++-v3/include/bits/uniform_int_dist.h  |  5 +++--<br>
 .../operators/values.cc                       | 22 +++++++++++++++++++<br>
 2 files changed, 25 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/libstdc++-v3/include/bits/uniform_int_dist.h b/libstdc++-v3/include/bits/uniform_int_dist.h<br>
index 9c5514c7c13..072c6351e1f 100644<br>
--- a/libstdc++-v3/include/bits/uniform_int_dist.h<br>
+++ b/libstdc++-v3/include/bits/uniform_int_dist.h<br>
@@ -262,18 +262,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION<br>
          static_assert(!_Wp_traits::__is_signed, "W must be unsigned");<br>
          static_assert(_Wp_traits::__digits == (2 * _Up_traits::__digits),<br>
                        "W must be twice as wide as U");<br>
+         constexpr auto __min = _Urbg::min();<br>
<br>
          // reference: Fast Random Integer Generation in an Interval<br>
          // ACM Transactions on Modeling and Computer Simulation 29 (1), 2019<br>
          // <a href="https://arxiv.org/abs/1805.10941" rel="noreferrer noreferrer noreferrer" target="_blank">https://arxiv.org/abs/1805.10941</a><br>
-         _Wp __product = _Wp(__g()) * _Wp(__range);<br>
+         _Wp __product = _Wp(__g() - __min) * _Wp(__range);<br>
          _Up __low = _Up(__product);<br>
          if (__low < __range)<br>
            {<br>
              _Up __threshold = -__range % __range;<br>
              while (__low < __threshold)<br>
                {<br>
-                 __product = _Wp(__g()) * _Wp(__range);<br>
+                 __product = _Wp(__g() - __min) * _Wp(__range);<br>
                  __low = _Up(__product);<br>
                }<br>
            }<br>
diff --git a/libstdc++-v3/testsuite/26_numerics/random/uniform_int_distribution/operators/values.cc b/libstdc++-v3/testsuite/26_numerics/random/uniform_int_distribution/operators/values.cc<br>
index 11758a3e2b6..fce14944d88 100644<br>
--- a/libstdc++-v3/testsuite/26_numerics/random/uniform_int_distribution/operators/values.cc<br>
+++ b/libstdc++-v3/testsuite/26_numerics/random/uniform_int_distribution/operators/values.cc<br>
@@ -21,6 +21,7 @@<br>
 // 26.5.8.2.1 Class template uniform_int_distribution [<a href="http://rand.dist.uni.int" rel="noreferrer noreferrer noreferrer" target="_blank">rand.dist.uni.int</a>]<br>
<br>
 #include <random><br>
+#include <cstdint><br>
 #include <functional><br>
 #include <testsuite_random.h><br>
<br>
@@ -32,6 +33,19 @@<br>
 # define ARGS<br>
 #endif<br>
<br>
+template<std::uint64_t Offset><br>
+struct shifted<br>
+{<br>
+  using result_type = std::uint64_t;<br>
+  static constexpr result_type min() { return Offset; }<br>
+  static constexpr result_type max() { return Offset + std::mt19937::max(); }<br>
+<br>
+  result_type operator()()<br>
+  { return Offset + eng(); }<br>
+<br>
+  std::mt19937 eng;<br>
+};<br>
+<br>
 void test01()<br>
 {<br>
   using namespace __gnu_test;<br>
@@ -49,6 +63,14 @@ void test01()<br>
   std::uniform_int_distribution<> uid3(1, 20);<br>
   auto buid3 = std::bind(uid3, eng);<br>
   testDiscreteDist<ARGS>(buid3, [](int n) { return uniform_int_pdf(n, 1, 20); } );<br>
+<br>
+  shifted<(std::uint64_t(1) << 16)> s16e;<br>
+  auto buid4 = std::bind(uid3, s16e);<br>
+  testDiscreteDist<ARGS>(buid4, [](int n) { return uniform_int_pdf(n, 1, 20); } );<br>
+<br>
+  shifted<(std::uint64_t(1) << 32)> s32e;<br>
+  auto buid5 = std::bind(uid3, s32e);<br>
+  testDiscreteDist<ARGS>(buid5, [](int n) { return uniform_int_pdf(n, 1, 20); } );<br>
 }<br>
<br>
 int main()<br>
-- <br>
2.55.0<br>
<br>
</blockquote></div></div></div>