abseil-cpp/absl/random/internal/fast_uniform_bits.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 #ifndef ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_
16 #define ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_
17 
18 #include <cstddef>
19 #include <cstdint>
20 #include <limits>
21 #include <type_traits>
22 
23 #include "absl/base/config.h"
24 #include "absl/meta/type_traits.h"
25 #include "absl/random/internal/traits.h"
26 
27 namespace absl {
29 namespace random_internal {
30 // Returns true if the input value is zero or a power of two. Useful for
31 // determining if the range of output values in a URBG
32 template <typename UIntType>
33 constexpr bool IsPowerOfTwoOrZero(UIntType n) {
34  return (n == 0) || ((n & (n - 1)) == 0);
35 }
36 
37 // Computes the length of the range of values producible by the URBG, or returns
38 // zero if that would encompass the entire range of representable values in
39 // URBG::result_type.
40 template <typename URBG>
41 constexpr typename URBG::result_type RangeSize() {
42  using result_type = typename URBG::result_type;
43  static_assert((URBG::max)() != (URBG::min)(), "URBG range cannot be 0.");
45  (URBG::min)() == std::numeric_limits<result_type>::lowest())
46  ? result_type{0}
47  : ((URBG::max)() - (URBG::min)() + result_type{1});
48 }
49 
50 // Computes the floor of the log. (i.e., std::floor(std::log2(N));
51 template <typename UIntType>
52 constexpr UIntType IntegerLog2(UIntType n) {
53  return (n <= 1) ? 0 : 1 + IntegerLog2(n >> 1);
54 }
55 
56 // Returns the number of bits of randomness returned through
57 // `PowerOfTwoVariate(urbg)`.
58 template <typename URBG>
59 constexpr size_t NumBits() {
60  return RangeSize<URBG>() == 0
61  ? std::numeric_limits<typename URBG::result_type>::digits
62  : IntegerLog2(RangeSize<URBG>());
63 }
64 
65 // Given a shift value `n`, constructs a mask with exactly the low `n` bits set.
66 // If `n == 0`, all bits are set.
67 template <typename UIntType>
68 constexpr UIntType MaskFromShift(size_t n) {
69  return ((n % std::numeric_limits<UIntType>::digits) == 0)
70  ? ~UIntType{0}
71  : (UIntType{1} << n) - UIntType{1};
72 }
73 
74 // Tags used to dispatch FastUniformBits::generate to the simple or more complex
75 // entropy extraction algorithm.
77 struct RejectionLoopTag {};
78 
79 // FastUniformBits implements a fast path to acquire uniform independent bits
80 // from a type which conforms to the [rand.req.urbg] concept.
81 // Parameterized by:
82 // `UIntType`: the result (output) type
83 //
84 // The std::independent_bits_engine [rand.adapt.ibits] adaptor can be
85 // instantiated from an existing generator through a copy or a move. It does
86 // not, however, facilitate the production of pseudorandom bits from an un-owned
87 // generator that will outlive the std::independent_bits_engine instance.
88 template <typename UIntType = uint64_t>
90  public:
91  using result_type = UIntType;
92 
93  static constexpr result_type(min)() { return 0; }
94  static constexpr result_type(max)() {
96  }
97 
98  template <typename URBG>
99  result_type operator()(URBG& g); // NOLINT(runtime/references)
100 
101  private:
102  static_assert(IsUnsigned<UIntType>::value,
103  "Class-template FastUniformBits<> must be parameterized using "
104  "an unsigned type.");
105 
106  // Generate() generates a random value, dispatched on whether
107  // the underlying URBG must use rejection sampling to generate a value,
108  // or whether a simplified loop will suffice.
109  template <typename URBG>
110  result_type Generate(URBG& g, // NOLINT(runtime/references)
112 
113  template <typename URBG>
114  result_type Generate(URBG& g, // NOLINT(runtime/references)
116 };
117 
118 template <typename UIntType>
119 template <typename URBG>
121 FastUniformBits<UIntType>::operator()(URBG& g) { // NOLINT(runtime/references)
122  // kRangeMask is the mask used when sampling variates from the URBG when the
123  // width of the URBG range is not a power of 2.
124  // Y = (2 ^ kRange) - 1
125  static_assert((URBG::max)() > (URBG::min)(),
126  "URBG::max and URBG::min may not be equal.");
127 
130  return Generate(g, tag{});
131 }
132 
133 template <typename UIntType>
134 template <typename URBG>
136 FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references)
138  // The simplified version of FastUniformBits works only on URBGs that have
139  // a range that is a power of 2. In this case we simply loop and shift without
140  // attempting to balance the bits across calls.
141  static_assert(IsPowerOfTwoOrZero(RangeSize<URBG>()),
142  "incorrect Generate tag for URBG instance");
143 
144  static constexpr size_t kResultBits =
145  std::numeric_limits<result_type>::digits;
146  static constexpr size_t kUrbgBits = NumBits<URBG>();
147  static constexpr size_t kIters =
148  (kResultBits / kUrbgBits) + (kResultBits % kUrbgBits != 0);
149  static constexpr size_t kShift = (kIters == 1) ? 0 : kUrbgBits;
150  static constexpr auto kMin = (URBG::min)();
151 
152  result_type r = static_cast<result_type>(g() - kMin);
153  for (size_t n = 1; n < kIters; ++n) {
154  r = (r << kShift) + static_cast<result_type>(g() - kMin);
155  }
156  return r;
157 }
158 
159 template <typename UIntType>
160 template <typename URBG>
162 FastUniformBits<UIntType>::Generate(URBG& g, // NOLINT(runtime/references)
164  static_assert(!IsPowerOfTwoOrZero(RangeSize<URBG>()),
165  "incorrect Generate tag for URBG instance");
166  using urbg_result_type = typename URBG::result_type;
167 
168  // See [rand.adapt.ibits] for more details on the constants calculated below.
169  //
170  // It is preferable to use roughly the same number of bits from each generator
171  // call, however this is only possible when the number of bits provided by the
172  // URBG is a divisor of the number of bits in `result_type`. In all other
173  // cases, the number of bits used cannot always be the same, but it can be
174  // guaranteed to be off by at most 1. Thus we run two loops, one with a
175  // smaller bit-width size (`kSmallWidth`) and one with a larger width size
176  // (satisfying `kLargeWidth == kSmallWidth + 1`). The loops are run
177  // `kSmallIters` and `kLargeIters` times respectively such
178  // that
179  //
180  // `kResultBits == kSmallIters * kSmallBits
181  // + kLargeIters * kLargeBits`
182  //
183  // where `kResultBits` is the total number of bits in `result_type`.
184  //
185  static constexpr size_t kResultBits =
186  std::numeric_limits<result_type>::digits; // w
187  static constexpr urbg_result_type kUrbgRange = RangeSize<URBG>(); // R
188  static constexpr size_t kUrbgBits = NumBits<URBG>(); // m
189 
190  // compute the initial estimate of the bits used.
191  // [rand.adapt.ibits] 2 (c)
192  static constexpr size_t kA = // ceil(w/m)
193  (kResultBits / kUrbgBits) + ((kResultBits % kUrbgBits) != 0); // n'
194 
195  static constexpr size_t kABits = kResultBits / kA; // w0'
196  static constexpr urbg_result_type kARejection =
197  ((kUrbgRange >> kABits) << kABits); // y0'
198 
199  // refine the selection to reduce the rejection frequency.
200  static constexpr size_t kTotalIters =
201  ((kUrbgRange - kARejection) <= (kARejection / kA)) ? kA : (kA + 1); // n
202 
203  // [rand.adapt.ibits] 2 (b)
204  static constexpr size_t kSmallIters =
205  kTotalIters - (kResultBits % kTotalIters); // n0
206  static constexpr size_t kSmallBits = kResultBits / kTotalIters; // w0
207  static constexpr urbg_result_type kSmallRejection =
208  ((kUrbgRange >> kSmallBits) << kSmallBits); // y0
209 
210  static constexpr size_t kLargeBits = kSmallBits + 1; // w0+1
211  static constexpr urbg_result_type kLargeRejection =
212  ((kUrbgRange >> kLargeBits) << kLargeBits); // y1
213 
214  //
215  // Because `kLargeBits == kSmallBits + 1`, it follows that
216  //
217  // `kResultBits == kSmallIters * kSmallBits + kLargeIters`
218  //
219  // and therefore
220  //
221  // `kLargeIters == kTotalWidth % kSmallWidth`
222  //
223  // Intuitively, each iteration with the large width accounts for one unit
224  // of the remainder when `kTotalWidth` is divided by `kSmallWidth`. As
225  // mentioned above, if the URBG width is a divisor of `kTotalWidth`, then
226  // there would be no need for any large iterations (i.e., one loop would
227  // suffice), and indeed, in this case, `kLargeIters` would be zero.
228  static_assert(kResultBits == kSmallIters * kSmallBits +
229  (kTotalIters - kSmallIters) * kLargeBits,
230  "Error in looping constant calculations.");
231 
232  // The small shift is essentially small bits, but due to the potential
233  // of generating a smaller result_type from a larger urbg type, the actual
234  // shift might be 0.
235  static constexpr size_t kSmallShift = kSmallBits % kResultBits;
236  static constexpr auto kSmallMask =
237  MaskFromShift<urbg_result_type>(kSmallShift);
238  static constexpr size_t kLargeShift = kLargeBits % kResultBits;
239  static constexpr auto kLargeMask =
240  MaskFromShift<urbg_result_type>(kLargeShift);
241 
242  static constexpr auto kMin = (URBG::min)();
243 
244  result_type s = 0;
245  for (size_t n = 0; n < kSmallIters; ++n) {
246  urbg_result_type v;
247  do {
248  v = g() - kMin;
249  } while (v >= kSmallRejection);
250 
251  s = (s << kSmallShift) + static_cast<result_type>(v & kSmallMask);
252  }
253 
254  for (size_t n = kSmallIters; n < kTotalIters; ++n) {
255  urbg_result_type v;
256  do {
257  v = g() - kMin;
258  } while (v >= kLargeRejection);
259 
260  s = (s << kLargeShift) + static_cast<result_type>(v & kLargeMask);
261  }
262  return s;
263 }
264 
265 } // namespace random_internal
267 } // namespace absl
268 
269 #endif // ABSL_RANDOM_INTERNAL_FAST_UNIFORM_BITS_H_
absl::random_internal::IntegerLog2
constexpr UIntType IntegerLog2(UIntType n)
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:52
absl::random_internal::FastUniformBits::Generate
result_type Generate(URBG &g, SimplifiedLoopTag)
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:136
absl::random_internal::FastUniformBits::min
static constexpr result_type() min()
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:93
absl::conditional_t
typename std::conditional< B, T, F >::type conditional_t
Definition: abseil-cpp/absl/meta/type_traits.h:634
absl::random_internal::FastUniformBits< uint64_t >::result_type
uint64_t result_type
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:91
absl::random_internal::NumBits
constexpr size_t NumBits()
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:59
absl::FormatConversionChar::s
@ s
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::random_internal::SimplifiedLoopTag
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:76
absl::random_internal::IsUnsigned
Definition: abseil-cpp/absl/random/internal/traits.h:83
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
tag
static void * tag(intptr_t t)
Definition: bad_client.cc:318
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
absl::random_internal::MaskFromShift
constexpr UIntType MaskFromShift(size_t n)
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:68
result_type
const typedef int * result_type
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:4325
absl::random_internal::FastUniformBits::operator()
result_type operator()(URBG &g)
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:121
min
#define min(a, b)
Definition: qsort.h:83
g
struct @717 g
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
absl::random_internal::FastUniformBits::max
static constexpr result_type() max()
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:94
fix_build_deps.r
r
Definition: fix_build_deps.py:491
kIters
constexpr int32_t kIters
Definition: abseil-cpp/absl/base/spinlock_test_common.cc:38
absl::random_internal::RejectionLoopTag
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:77
absl::random_internal::IsPowerOfTwoOrZero
constexpr bool IsPowerOfTwoOrZero(UIntType n)
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:33
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::random_internal::RangeSize
constexpr URBG::result_type RangeSize()
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:41
absl::random_internal::FastUniformBits
Definition: abseil-cpp/absl/random/internal/fast_uniform_bits.h:89


grpc
Author(s):
autogenerated on Fri May 16 2025 02:58:22