ExRandom  3.0
unit_exponential_dist.hpp
Go to the documentation of this file.
1 /**
2  * @file unit_exponential_dist.hpp
3  * @author Charles Karney <charles.karney@sri.com>
4  * @brief Definition of unit_exponential_dist
5  *
6  * Copyright (c) Charles Karney (2014) and licensed under the MIT/X11 License.
7  * For more information, see http://exrandom.sourceforge.net/
8  */
9 
10 #if !defined(EXRANDOM_UNIT_EXPONENTIAL_DIST_HPP)
11 #define EXRANDOM_UNIT_EXPONENTIAL_DIST_HPP 1
12 
13 #include <exrandom/u_rand.hpp>
14 
15 #if defined(_MSC_VER)
16 // Squelch warnings about constant conditional expressions
17 # pragma warning (push)
18 # pragma warning (disable: 4127)
19 #endif
20 
21 namespace exrandom {
22 
23  /**
24  * @brief Sample u-rands exactly from the unit exponential distribution.
25  *
26  * This samples from the unit exponential distribution P(x) = exp(&minus;x)
27  * for x &gt; 0. This implements Algorithms E and V.
28  *
29  * @tparam digit_gen the type of digit generator.
30  * @tparam bit_optimized if true use Algorithm E, else use Algorithm V.
31  *
32  * This class allows a u-rand to be returned via the
33  * unit_exponential_dist::generate member function or a floating point
34  * result via the unit_exponential_dist::value<RealType> member function.
35  *
36  * See unit_exponential_distribution for a simpler interface to sampling
37  * exponential deviates. (But, you can't obtain u-rands with this class and
38  * the constructor locks you into a specific floating point type.)
39  *
40  * If bit_optimized is true, digit_gen::base must be even.
41  */
42  template<typename digit_gen, bool bit_optimized = true>
44  public:
45  /**
46  * The constructor.
47  *
48  * @param D a reference to the digit generator to be used.
49  */
50  unit_exponential_dist(digit_gen& D) : _D(D), _v(D), _w(D), _x(D) {}
51 
52  /**
53  * Generate the next deviate as a u_rand.
54  *
55  * @tparam Generator the type of g.
56  * @param g the random generator engine.
57  * @param[out] x the u_rand to set.
58  */
59  template<typename Generator>
60  void generate(Generator& g, u_rand<digit_gen>& x) {
61  // A simple rejection method gives the 1/2 fractional part. The number of
62  // rejections gives the multiples of 1/2.
63  // bits: used fract
64  // original stats: 9.31615 2.05429
65  // new stats: 7.23226 1.74305
66  int k = 0;
67  while (!F(g, x)) ++k; // Executed 1/(1 - exp(-1/2)) on average
68  // If k is odd, add base/2 to first digit (allowing for base = 2^32)
69  if (bit_optimized && (k % 2) != 0) x.rawdigit(0) += (bm1 - 1U) / 2U + 1U;
70  x.set_integer(bit_optimized ? k/2 : k);
71  return;
72  }
73 
74  /**
75  * Generate the next deviate and round it to a floating point number.
76  *
77  * @tparam RealType the floating point type of the result.
78  * @tparam Generator the type of g.
79  * @param g the random generator engine.
80  * @return the exponential deviate.
81  */
82  template<typename RealType, typename Generator>
83  RealType value(Generator& g) {
84  generate(g, _x);
85  return _x.template value<RealType>(g);
86  }
87 
88  /**
89  * @return a reference to the digit generator used in the constructor.
90  */
91  digit_gen& digit_generator() const { return _D; }
92 
93  /**
94  * The base of the digit generator.
95  */
96  static const uint_t base = digit_gen::base;
97  private:
98  static const uint_t bm1 = digit_gen::max_value;
99  // Disable copy assignment
100  unit_exponential_dist& operator=(const unit_exponential_dist&);
101  digit_gen& _D;
102  static_assert(!bit_optimized || (bm1 & 1U),
103  "unit_exponential_dist: base must be even");
104  u_rand<digit_gen> _v, _w, _x; // temporary storage
105  template<typename Generator>
106  bool F(Generator& g, u_rand<digit_gen>& p) {
107  p.init();
108  // The early bale out
109  if (bit_optimized && !p.less_than_half(g)) return false;
110  // Implement the von Neumann algorithm
111  if (!_w.init().less_than(g, p)) return true; // if (w < p)
112  for (;;) { // Unroll loop to avoid copying
113  if (!_v.init().less_than(g, _w)) return false; // if (v < w)
114  if (!_w.init().less_than(g, _v)) return true; // if (w < v)
115  }
116  }
117 
118  };
119 
120 }
121 
122 #if defined(_MSC_VER)
123 # pragma warning (pop)
124 #endif
125 
126 #endif // EXRANDOM_UNIT_EXPONENTIAL_DIST_HPP
void generate(Generator &g, u_rand< digit_gen > &x)
Definition of u_rand.
u_rand & init()
Definition: u_rand.hpp:123
Sample u-rands exactly from the unit exponential distribution.
uint_t rawdigit(size_t k) const
Definition: u_rand.hpp:179
The common namespace.
Definition: aux_info.hpp:18
The machinery to handle u-rands, arbitrary precision random deviates.
Definition: u_rand.hpp:105
void set_integer(unsigned n)
Definition: u_rand.hpp:155
bool less_than_half(Generator &g)
Definition: u_rand.hpp:213