abseil-cpp/absl/random/uniform_int_distribution.h
Go to the documentation of this file.
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // -----------------------------------------------------------------------------
16 // File: uniform_int_distribution.h
17 // -----------------------------------------------------------------------------
18 //
19 // This header defines a class for representing a uniform integer distribution
20 // over the closed (inclusive) interval [a,b]. You use this distribution in
21 // combination with an Abseil random bit generator to produce random values
22 // according to the rules of the distribution.
23 //
24 // `absl::uniform_int_distribution` is a drop-in replacement for the C++11
25 // `std::uniform_int_distribution` [rand.dist.uni.int] but is considerably
26 // faster than the libstdc++ implementation.
27 
28 #ifndef ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_
29 #define ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_
30 
31 #include <cassert>
32 #include <istream>
33 #include <limits>
34 #include <type_traits>
35 
36 #include "absl/base/optimization.h"
37 #include "absl/random/internal/fast_uniform_bits.h"
38 #include "absl/random/internal/iostream_state_saver.h"
39 #include "absl/random/internal/traits.h"
40 #include "absl/random/internal/wide_multiply.h"
41 
42 namespace absl {
44 
45 // absl::uniform_int_distribution<T>
46 //
47 // This distribution produces random integer values uniformly distributed in the
48 // closed (inclusive) interval [a, b].
49 //
50 // Example:
51 //
52 // absl::BitGen gen;
53 //
54 // // Use the distribution to produce a value between 1 and 6, inclusive.
55 // int die_roll = absl::uniform_int_distribution<int>(1, 6)(gen);
56 //
57 template <typename IntType = int>
58 class uniform_int_distribution {
59  private:
60  using unsigned_type =
62 
63  public:
64  using result_type = IntType;
65 
66  class param_type {
67  public:
69 
70  explicit param_type(
71  result_type lo = 0,
73  : lo_(lo),
74  range_(static_cast<unsigned_type>(hi) -
75  static_cast<unsigned_type>(lo)) {
76  // [rand.dist.uni.int] precondition 2
77  assert(lo <= hi);
78  }
79 
80  result_type a() const { return lo_; }
81  result_type b() const {
82  return static_cast<result_type>(static_cast<unsigned_type>(lo_) + range_);
83  }
84 
85  friend bool operator==(const param_type& a, const param_type& b) {
86  return a.lo_ == b.lo_ && a.range_ == b.range_;
87  }
88 
89  friend bool operator!=(const param_type& a, const param_type& b) {
90  return !(a == b);
91  }
92 
93  private:
95  unsigned_type range() const { return range_; }
96 
99 
101  "Class-template absl::uniform_int_distribution<> must be "
102  "parameterized using an integral type.");
103  }; // param_type
104 
106 
108  result_type lo,
110  : param_(lo, hi) {}
111 
113 
114  // uniform_int_distribution<T>::reset()
115  //
116  // Resets the uniform int distribution. Note that this function has no effect
117  // because the distribution already produces independent values.
118  void reset() {}
119 
120  template <typename URBG>
121  result_type operator()(URBG& gen) { // NOLINT(runtime/references)
122  return (*this)(gen, param());
123  }
124 
125  template <typename URBG>
127  URBG& gen, const param_type& param) { // NOLINT(runtime/references)
128  return static_cast<result_type>(param.a() + Generate(gen, param.range()));
129  }
130 
131  result_type a() const { return param_.a(); }
132  result_type b() const { return param_.b(); }
133 
134  param_type param() const { return param_; }
135  void param(const param_type& params) { param_ = params; }
136 
137  result_type(min)() const { return a(); }
138  result_type(max)() const { return b(); }
139 
141  const uniform_int_distribution& b) {
142  return a.param_ == b.param_;
143  }
145  const uniform_int_distribution& b) {
146  return !(a == b);
147  }
148 
149  private:
150  // Generates a value in the *closed* interval [0, R]
151  template <typename URBG>
152  unsigned_type Generate(URBG& g, // NOLINT(runtime/references)
153  unsigned_type R);
155 };
156 
157 // -----------------------------------------------------------------------------
158 // Implementation details follow
159 // -----------------------------------------------------------------------------
160 template <typename CharT, typename Traits, typename IntType>
161 std::basic_ostream<CharT, Traits>& operator<<(
162  std::basic_ostream<CharT, Traits>& os,
164  using stream_type =
167  os << static_cast<stream_type>(x.a()) << os.fill()
168  << static_cast<stream_type>(x.b());
169  return os;
170 }
171 
172 template <typename CharT, typename Traits, typename IntType>
173 std::basic_istream<CharT, Traits>& operator>>(
174  std::basic_istream<CharT, Traits>& is,
176  using param_type = typename uniform_int_distribution<IntType>::param_type;
178  using stream_type =
180 
181  stream_type a;
182  stream_type b;
183 
185  is >> a >> b;
186  if (!is.fail()) {
187  x.param(
188  param_type(static_cast<result_type>(a), static_cast<result_type>(b)));
189  }
190  return is;
191 }
192 
193 template <typename IntType>
194 template <typename URBG>
197  URBG& g, // NOLINT(runtime/references)
200  unsigned_type bits = fast_bits(g);
201  const unsigned_type Lim = R + 1;
202  if ((R & Lim) == 0) {
203  // If the interval's length is a power of two range, just take the low bits.
204  return bits & R;
205  }
206 
207  // Generates a uniform variate on [0, Lim) using fixed-point multiplication.
208  // The above fast-path guarantees that Lim is representable in unsigned_type.
209  //
210  // Algorithm adapted from
211  // http://lemire.me/blog/2016/06/30/fast-random-shuffling/, with added
212  // explanation.
213  //
214  // The algorithm creates a uniform variate `bits` in the interval [0, 2^N),
215  // and treats it as the fractional part of a fixed-point real value in [0, 1),
216  // multiplied by 2^N. For example, 0.25 would be represented as 2^(N - 2),
217  // because 2^N * 0.25 == 2^(N - 2).
218  //
219  // Next, `bits` and `Lim` are multiplied with a wide-multiply to bring the
220  // value into the range [0, Lim). The integral part (the high word of the
221  // multiplication result) is then very nearly the desired result. However,
222  // this is not quite accurate; viewing the multiplication result as one
223  // double-width integer, the resulting values for the sample are mapped as
224  // follows:
225  //
226  // If the result lies in this interval: Return this value:
227  // [0, 2^N) 0
228  // [2^N, 2 * 2^N) 1
229  // ... ...
230  // [K * 2^N, (K + 1) * 2^N) K
231  // ... ...
232  // [(Lim - 1) * 2^N, Lim * 2^N) Lim - 1
233  //
234  // While all of these intervals have the same size, the result of `bits * Lim`
235  // must be a multiple of `Lim`, and not all of these intervals contain the
236  // same number of multiples of `Lim`. In particular, some contain
237  // `F = floor(2^N / Lim)` and some contain `F + 1 = ceil(2^N / Lim)`. This
238  // difference produces a small nonuniformity, which is corrected by applying
239  // rejection sampling to one of the values in the "larger intervals" (i.e.,
240  // the intervals containing `F + 1` multiples of `Lim`.
241  //
242  // An interval contains `F + 1` multiples of `Lim` if and only if its smallest
243  // value modulo 2^N is less than `2^N % Lim`. The unique value satisfying
244  // this property is used as the one for rejection. That is, a value of
245  // `bits * Lim` is rejected if `(bit * Lim) % 2^N < (2^N % Lim)`.
246 
248  auto product = helper::multiply(bits, Lim);
249 
250  // Two optimizations here:
251  // * Rejection occurs with some probability less than 1/2, and for reasonable
252  // ranges considerably less (in particular, less than 1/(F+1)), so
253  // ABSL_PREDICT_FALSE is apt.
254  // * `Lim` is an overestimate of `threshold`, and doesn't require a divide.
255  if (ABSL_PREDICT_FALSE(helper::lo(product) < Lim)) {
256  // This quantity is exactly equal to `2^N % Lim`, but does not require high
257  // precision calculations: `2^N % Lim` is congruent to `(2^N - Lim) % Lim`.
258  // Ideally this could be expressed simply as `-X` rather than `2^N - X`, but
259  // for types smaller than int, this calculation is incorrect due to integer
260  // promotion rules.
261  const unsigned_type threshold =
262  ((std::numeric_limits<unsigned_type>::max)() - Lim + 1) % Lim;
263  while (helper::lo(product) < threshold) {
264  bits = fast_bits(g);
265  product = helper::multiply(bits, Lim);
266  }
267  }
268 
269  return helper::hi(product);
270 }
271 
273 } // namespace absl
274 
275 #endif // ABSL_RANDOM_UNIFORM_INT_DISTRIBUTION_H_
ABSL_PREDICT_FALSE
#define ABSL_PREDICT_FALSE(x)
Definition: abseil-cpp/absl/base/optimization.h:180
absl::uniform_int_distribution::uniform_int_distribution
uniform_int_distribution(const param_type &param)
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:112
absl::uniform_int_distribution::operator==
friend bool operator==(const uniform_int_distribution &a, const uniform_int_distribution &b)
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:140
absl::uniform_int_distribution::min
result_type() min() const
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:137
absl::uniform_int_distribution::param_type::uniform_int_distribution
friend class uniform_int_distribution
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:94
absl::uniform_int_distribution::operator()
result_type operator()(URBG &gen)
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:121
absl::uniform_int_distribution::param_type
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:66
absl::random_internal::make_istream_state_saver
istream_state_saver< std::basic_istream< CharT, Traits > > make_istream_state_saver(std::basic_istream< CharT, Traits > &is, std::ios_base::fmtflags flags=std::ios_base::dec|std::ios_base::scientific|std::ios_base::skipws)
Definition: abseil-cpp/absl/random/internal/iostream_state_saver.h:149
absl::operator<<
ABSL_NAMESPACE_BEGIN std::ostream & operator<<(std::ostream &os, absl::LogSeverity s)
Definition: abseil-cpp/absl/base/log_severity.cc:24
absl::uniform_int_distribution::param_type::range
unsigned_type range() const
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:95
absl::uniform_int_distribution::param_type::operator!=
friend bool operator!=(const param_type &a, const param_type &b)
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:89
absl::uniform_int_distribution::result_type
IntType result_type
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:64
absl::uniform_int_distribution
Definition: abseil-cpp/absl/random/internal/uniform_helper.h:30
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
absl::random_internal::make_unsigned_bits::type
typename unsigned_bits< std::numeric_limits< typename MakeUnsigned< IntType >::type >::digits >::type type
Definition: abseil-cpp/absl/random/internal/traits.h:129
absl::random_internal::IsIntegral
Definition: abseil-cpp/absl/random/internal/traits.h:65
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::random_internal::wide_multiply
Definition: abseil-cpp/absl/random/internal/wide_multiply.h:39
absl::random_internal::stream_format_type
Definition: abseil-cpp/absl/random/internal/iostream_state_saver.h:174
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::uniform_int_distribution::Generate
unsigned_type Generate(URBG &g, unsigned_type R)
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
absl::uniform_int_distribution::param_type::param_type
param_type(result_type lo=0, result_type hi=(std::numeric_limits< result_type >::max)())
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:70
absl::uniform_int_distribution::b
result_type b() const
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:132
result_type
const typedef int * result_type
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:4325
absl::uniform_int_distribution::param_type::lo_
result_type lo_
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:97
absl::uniform_int_distribution::param_type::operator==
friend bool operator==(const param_type &a, const param_type &b)
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:85
bits
OPENSSL_EXPORT ASN1_BIT_STRING * bits
Definition: x509v3.h:482
absl::uniform_int_distribution::reset
void reset()
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:118
absl::uniform_int_distribution::param
param_type param() const
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:134
absl::uniform_int_distribution::param_type::b
result_type b() const
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:81
x
int x
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3610
gen
OPENSSL_EXPORT GENERAL_NAME * gen
Definition: x509v3.h:495
absl::uniform_int_distribution::max
result_type() max() const
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:138
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
g
struct @717 g
absl::uniform_int_distribution::operator()
result_type operator()(URBG &gen, const param_type &param)
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:126
absl::operator>>
constexpr uint128 operator>>(uint128 lhs, int amount)
Definition: abseil-cpp/absl/numeric/int128.h:917
absl::uniform_int_distribution::param_type::a
result_type a() const
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:80
absl::uniform_int_distribution::param
void param(const param_type &params)
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:135
absl::uniform_int_distribution::uniform_int_distribution
uniform_int_distribution()
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:105
absl::uniform_int_distribution::operator!=
friend bool operator!=(const uniform_int_distribution &a, const uniform_int_distribution &b)
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:144
absl::uniform_int_distribution::a
result_type a() const
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:131
absl::uniform_int_distribution::unsigned_type
typename random_internal::make_unsigned_bits< IntType >::type unsigned_type
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:61
stream_type
stream_type
Definition: task.h:81
absl::uniform_int_distribution::param_
param_type param_
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:154
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::random_internal::make_ostream_state_saver
ostream_state_saver< std::basic_ostream< CharT, Traits > > make_ostream_state_saver(std::basic_ostream< CharT, Traits > &os, std::ios_base::fmtflags flags=std::ios_base::dec|std::ios_base::left|std::ios_base::scientific)
Definition: abseil-cpp/absl/random/internal/iostream_state_saver.h:82
absl::uniform_int_distribution::param_type::range_
unsigned_type range_
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:98
absl::uniform_int_distribution::uniform_int_distribution
uniform_int_distribution(result_type lo, result_type hi=(std::numeric_limits< result_type >::max)())
Definition: abseil-cpp/absl/random/uniform_int_distribution.h:107
absl::random_internal::FastUniformBits
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:89


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:44