abseil-cpp/absl/random/gaussian_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 #ifndef ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_
16 #define ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_
17 
18 // absl::gaussian_distribution implements the Ziggurat algorithm
19 // for generating random gaussian numbers.
20 //
21 // Implementation based on "The Ziggurat Method for Generating Random Variables"
22 // by George Marsaglia and Wai Wan Tsang: http://www.jstatsoft.org/v05/i08/
23 //
24 
25 #include <cmath>
26 #include <cstdint>
27 #include <istream>
28 #include <limits>
29 #include <type_traits>
30 
31 #include "absl/base/config.h"
32 #include "absl/random/internal/fast_uniform_bits.h"
33 #include "absl/random/internal/generate_real.h"
34 #include "absl/random/internal/iostream_state_saver.h"
35 
36 namespace absl {
38 namespace random_internal {
39 
40 // absl::gaussian_distribution_base implements the underlying ziggurat algorithm
41 // using the ziggurat tables generated by the gaussian_distribution_gentables
42 // binary.
43 //
44 // The specific algorithm has some of the improvements suggested by the
45 // 2005 paper, "An Improved Ziggurat Method to Generate Normal Random Samples",
46 // Jurgen A Doornik. (https://www.doornik.com/research/ziggurat.pdf)
48  public:
49  template <typename URBG>
50  inline double zignor(URBG& g); // NOLINT(runtime/references)
51 
52  private:
53  friend class TableGenerator;
54 
55  template <typename URBG>
56  inline double zignor_fallback(URBG& g, // NOLINT(runtime/references)
57  bool neg);
58 
59  // Constants used for the gaussian distribution.
60  static constexpr double kR = 3.442619855899; // Start of the tail.
61  static constexpr double kRInv = 0.29047645161474317; // ~= (1.0 / kR) .
62  static constexpr double kV = 9.91256303526217e-3;
63  static constexpr uint64_t kMask = 0x07f;
64 
65  // The ziggurat tables store the pdf(f) and inverse-pdf(x) for equal-area
66  // points on one-half of the normal distribution, where the pdf function,
67  // pdf = e ^ (-1/2 *x^2), assumes that the mean = 0 & stddev = 1.
68  //
69  // These tables are just over 2kb in size; larger tables might improve the
70  // distributions, but also lead to more cache pollution.
71  //
72  // x = {3.71308, 3.44261, 3.22308, ..., 0}
73  // f = {0.00101, 0.00266, 0.00554, ..., 1}
74  struct Tables {
75  double x[kMask + 2];
76  double f[kMask + 2];
77  };
78  static const Tables zg_;
80 };
81 
82 } // namespace random_internal
83 
84 // absl::gaussian_distribution:
85 // Generates a number conforming to a Gaussian distribution.
86 template <typename RealType = double>
88  public:
89  using result_type = RealType;
90 
91  class param_type {
92  public:
94 
96  : mean_(mean), stddev_(stddev) {}
97 
98  // Returns the mean distribution parameter. The mean specifies the location
99  // of the peak. The default value is 0.0.
100  result_type mean() const { return mean_; }
101 
102  // Returns the deviation distribution parameter. The default value is 1.0.
103  result_type stddev() const { return stddev_; }
104 
105  friend bool operator==(const param_type& a, const param_type& b) {
106  return a.mean_ == b.mean_ && a.stddev_ == b.stddev_;
107  }
108 
109  friend bool operator!=(const param_type& a, const param_type& b) {
110  return !(a == b);
111  }
112 
113  private:
116 
117  static_assert(
119  "Class-template absl::gaussian_distribution<> must be parameterized "
120  "using a floating-point type.");
121  };
122 
124 
126  : param_(mean, stddev) {}
127 
128  explicit gaussian_distribution(const param_type& p) : param_(p) {}
129 
130  void reset() {}
131 
132  // Generating functions
133  template <typename URBG>
134  result_type operator()(URBG& g) { // NOLINT(runtime/references)
135  return (*this)(g, param_);
136  }
137 
138  template <typename URBG>
139  result_type operator()(URBG& g, // NOLINT(runtime/references)
140  const param_type& p);
141 
142  param_type param() const { return param_; }
143  void param(const param_type& p) { param_ = p; }
144 
145  result_type(min)() const {
146  return -std::numeric_limits<result_type>::infinity();
147  }
148  result_type(max)() const {
149  return std::numeric_limits<result_type>::infinity();
150  }
151 
152  result_type mean() const { return param_.mean(); }
153  result_type stddev() const { return param_.stddev(); }
154 
155  friend bool operator==(const gaussian_distribution& a,
156  const gaussian_distribution& b) {
157  return a.param_ == b.param_;
158  }
159  friend bool operator!=(const gaussian_distribution& a,
160  const gaussian_distribution& b) {
161  return a.param_ != b.param_;
162  }
163 
164  private:
166 };
167 
168 // --------------------------------------------------------------------------
169 // Implementation details only below
170 // --------------------------------------------------------------------------
171 
172 template <typename RealType>
173 template <typename URBG>
176  URBG& g, // NOLINT(runtime/references)
177  const param_type& p) {
178  return p.mean() + p.stddev() * static_cast<result_type>(zignor(g));
179 }
180 
181 template <typename CharT, typename Traits, typename RealType>
182 std::basic_ostream<CharT, Traits>& operator<<(
183  std::basic_ostream<CharT, Traits>& os, // NOLINT(runtime/references)
187  os << x.mean() << os.fill() << x.stddev();
188  return os;
189 }
190 
191 template <typename CharT, typename Traits, typename RealType>
192 std::basic_istream<CharT, Traits>& operator>>(
193  std::basic_istream<CharT, Traits>& is, // NOLINT(runtime/references)
194  gaussian_distribution<RealType>& x) { // NOLINT(runtime/references)
196  using param_type = typename gaussian_distribution<RealType>::param_type;
197 
199  auto mean = random_internal::read_floating_point<result_type>(is);
200  if (is.fail()) return is;
201  auto stddev = random_internal::read_floating_point<result_type>(is);
202  if (!is.fail()) {
203  x.param(param_type(mean, stddev));
204  }
205  return is;
206 }
207 
208 namespace random_internal {
209 
210 template <typename URBG>
211 inline double gaussian_distribution_base::zignor_fallback(URBG& g, bool neg) {
214 
215  // This fallback path happens approximately 0.05% of the time.
216  double x, y;
217  do {
218  // kRInv = 1/r, U(0, 1)
219  x = kRInv *
220  std::log(GenerateRealFromBits<double, GeneratePositiveTag, false>(
221  fast_u64_(g)));
222  y = -std::log(
223  GenerateRealFromBits<double, GeneratePositiveTag, false>(fast_u64_(g)));
224  } while ((y + y) < (x * x));
225  return neg ? (x - kR) : (kR - x);
226 }
227 
228 template <typename URBG>
230  URBG& g) { // NOLINT(runtime/references)
234 
235  while (true) {
236  // We use a single uint64_t to generate both a double and a strip.
237  // These bits are unused when the generated double is > 1/2^5.
238  // This may introduce some bias from the duplicated low bits of small
239  // values (those smaller than 1/2^5, which all end up on the left tail).
241  int i = static_cast<int>(bits & kMask); // pick a random strip
242  double j = GenerateRealFromBits<double, GenerateSignedTag, false>(
243  bits); // U(-1, 1)
244  const double x = j * zg_.x[i];
245 
246  // Retangular box. Handles >97% of all cases.
247  // For any given box, this handles between 75% and 99% of values.
248  // Equivalent to U(01) < (x[i+1] / x[i]), and when i == 0, ~93.5%
249  if (std::abs(x) < zg_.x[i + 1]) {
250  return x;
251  }
252 
253  // i == 0: Base box. Sample using a ratio of uniforms.
254  if (i == 0) {
255  // This path happens about 0.05% of the time.
256  return zignor_fallback(g, j < 0);
257  }
258 
259  // i > 0: Wedge samples using precomputed values.
260  double v = GenerateRealFromBits<double, GeneratePositiveTag, false>(
261  fast_u64_(g)); // U(0, 1)
262  if ((zg_.f[i + 1] + v * (zg_.f[i] - zg_.f[i + 1])) <
263  std::exp(-0.5 * x * x)) {
264  return x;
265  }
266 
267  // The wedge was missed; reject the value and try again.
268  }
269 }
270 
271 } // namespace random_internal
273 } // namespace absl
274 
275 #endif // ABSL_RANDOM_GAUSSIAN_DISTRIBUTION_H_
absl::random_internal::gaussian_distribution_base
Definition: abseil-cpp/absl/random/gaussian_distribution.h:47
absl::gaussian_distribution::operator()
result_type operator()(URBG &g)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:134
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::random_internal::TableGenerator
Definition: abseil-cpp/absl/random/internal/gaussian_distribution_gentables.cc:59
absl::gaussian_distribution::stddev
result_type stddev() const
Definition: abseil-cpp/absl/random/gaussian_distribution.h:153
absl::operator<<
ABSL_NAMESPACE_BEGIN std::ostream & operator<<(std::ostream &os, absl::LogSeverity s)
Definition: abseil-cpp/absl/base/log_severity.cc:24
y
const double y
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3611
absl::gaussian_distribution::param_type
Definition: abseil-cpp/absl/random/gaussian_distribution.h:91
absl::gaussian_distribution::min
result_type() min() const
Definition: abseil-cpp/absl/random/gaussian_distribution.h:145
absl::random_internal::gaussian_distribution_base::Tables
Definition: abseil-cpp/absl/random/gaussian_distribution.h:74
absl::random_internal::gaussian_distribution_base::kR
static constexpr double kR
Definition: abseil-cpp/absl/random/gaussian_distribution.h:60
absl::random_internal::GenerateSignedTag
Definition: abseil-cpp/absl/random/internal/generate_real.h:38
absl::gaussian_distribution::operator!=
friend bool operator!=(const gaussian_distribution &a, const gaussian_distribution &b)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:159
absl::random_internal::gaussian_distribution_base::Tables::x
double x[kMask+2]
Definition: abseil-cpp/absl/random/gaussian_distribution.h:75
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
absl::random_internal::GeneratePositiveTag
Definition: abseil-cpp/absl/random/internal/generate_real.h:36
absl::random_internal::gaussian_distribution_base::kRInv
static constexpr double kRInv
Definition: abseil-cpp/absl/random/gaussian_distribution.h:61
absl::gaussian_distribution::param
void param(const param_type &p)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:143
absl::gaussian_distribution::param_type::stddev
result_type stddev() const
Definition: abseil-cpp/absl/random/gaussian_distribution.h:103
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
absl::random_internal::gaussian_distribution_base::zignor
double zignor(URBG &g)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:229
absl::gaussian_distribution
Definition: abseil-cpp/absl/random/gaussian_distribution.h:87
absl::gaussian_distribution::mean
result_type mean() const
Definition: abseil-cpp/absl/random/gaussian_distribution.h:152
absl::random_internal::GenerateRealFromBits
RealType GenerateRealFromBits(uint64_t bits, int exp_bias=0)
Definition: abseil-cpp/absl/random/internal/generate_real.h:70
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::gaussian_distribution::param_type::stddev_
result_type stddev_
Definition: abseil-cpp/absl/random/gaussian_distribution.h:115
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
result_type
const typedef int * result_type
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:4325
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
absl::random_internal::gaussian_distribution_base::zg_
static const Tables zg_
Definition: abseil-cpp/absl/random/gaussian_distribution.h:78
bits
OPENSSL_EXPORT ASN1_BIT_STRING * bits
Definition: x509v3.h:482
absl::gaussian_distribution::param_type::operator!=
friend bool operator!=(const param_type &a, const param_type &b)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:109
absl::random_internal::gaussian_distribution_base::fast_u64_
random_internal::FastUniformBits< uint64_t > fast_u64_
Definition: abseil-cpp/absl/random/gaussian_distribution.h:79
x
int x
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3610
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
g
struct @717 g
absl::gaussian_distribution::gaussian_distribution
gaussian_distribution(const param_type &p)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:128
absl::gaussian_distribution::param_type::param_type
param_type(result_type mean=0, result_type stddev=1)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:95
ABSL_DLL
#define ABSL_DLL
Definition: third_party/abseil-cpp/absl/base/config.h:746
absl::random_internal::stream_precision_helper
Definition: abseil-cpp/absl/random/internal/iostream_state_saver.h:107
absl::gaussian_distribution::result_type
RealType result_type
Definition: abseil-cpp/absl/random/gaussian_distribution.h:89
value
const char * value
Definition: hpack_parser_table.cc:165
absl::operator>>
constexpr uint128 operator>>(uint128 lhs, int amount)
Definition: abseil-cpp/absl/numeric/int128.h:917
absl::gaussian_distribution::param_type::operator==
friend bool operator==(const param_type &a, const param_type &b)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:105
absl::gaussian_distribution::gaussian_distribution
gaussian_distribution()
Definition: abseil-cpp/absl/random/gaussian_distribution.h:123
absl::gaussian_distribution::gaussian_distribution
gaussian_distribution(result_type mean, result_type stddev=1)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:125
absl::gaussian_distribution::param
param_type param() const
Definition: abseil-cpp/absl/random/gaussian_distribution.h:142
log
bool log
Definition: abseil-cpp/absl/synchronization/mutex.cc:310
absl::random_internal::gaussian_distribution_base::Tables::f
double f[kMask+2]
Definition: abseil-cpp/absl/random/gaussian_distribution.h:76
absl::gaussian_distribution::param_type::mean
result_type mean() const
Definition: abseil-cpp/absl/random/gaussian_distribution.h:100
absl::random_internal::gaussian_distribution_base::kMask
static constexpr uint64_t kMask
Definition: abseil-cpp/absl/random/gaussian_distribution.h:63
absl::gaussian_distribution::param_type::mean_
result_type mean_
Definition: abseil-cpp/absl/random/gaussian_distribution.h:114
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::gaussian_distribution::max
result_type() max() const
Definition: abseil-cpp/absl/random/gaussian_distribution.h:148
absl::gaussian_distribution::param_
param_type param_
Definition: abseil-cpp/absl/random/gaussian_distribution.h:165
absl::gaussian_distribution::reset
void reset()
Definition: abseil-cpp/absl/random/gaussian_distribution.h:130
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::gaussian_distribution::operator==
friend bool operator==(const gaussian_distribution &a, const gaussian_distribution &b)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:155
absl::random_internal::gaussian_distribution_base::zignor_fallback
double zignor_fallback(URBG &g, bool neg)
Definition: abseil-cpp/absl/random/gaussian_distribution.h:211
absl::random_internal::FastUniformBits< uint64_t >
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


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