RandomLib  1.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
ExponentialProb.hpp
Go to the documentation of this file.
1 /**
2  * \file ExponentialProb.hpp
3  * \brief Header for ExponentialProb
4  *
5  * Return true with probabililty exp(-\e p).
6  *
7  * Copyright (c) Charles Karney (2006-2012) <charles@karney.com> and licensed
8  * under the MIT/X11 License. For more information, see
9  * http://randomlib.sourceforge.net/
10  **********************************************************************/
11 
12 #if !defined(RANDOMLIB_EXPONENTIALPROB_HPP)
13 #define RANDOMLIB_EXPONENTIALPROB_HPP 1
14 
15 #include <vector>
16 #include <limits>
17 
18 #if defined(_MSC_VER)
19 // Squelch warnings about constant conditional expressions
20 # pragma warning (push)
21 # pragma warning (disable: 4127)
22 #endif
23 
24 namespace RandomLib {
25  /**
26  * \brief The exponential probability.
27  *
28  * Return true with probability exp(&minus;\e p). Basic method taken from:\n
29  * J. von Neumann,\n Various Techniques used in Connection with Random
30  * Digits,\n J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38
31  * (1951),\n reprinted in Collected Works, Vol. 5, 768--770 (Pergammon,
32  * 1963).\n See also the references given for the ExactExponential class.
33  *
34  * Here the method is extended to be exact by generating sufficient bits in
35  * the random numbers in the algorithm to allow the unambiguous comparisons
36  * to be made.
37  *
38  * Here's one way of sampling from a normal distribution with zero mean and
39  * unit variance in the interval [&minus;1,1] with reasonable accuracy:
40  * \code
41  #include <RandomLib/Random.hpp>
42  #include <RandomLib/ExponentialProb.hpp>
43 
44  double Normal(RandomLib::Random& r) {
45  double x;
46  RandomLib::ExponentialProb e;
47  do
48  x = r.FloatW();
49  while ( !e(r, - 0.5 * x * x) );
50  return x;
51  }
52  \endcode
53  * (Note that the ExactNormal class samples from the normal distribution
54  * exactly.)
55  *
56  * This class uses a mutable private vector. So a single ExponentialProb
57  * object cannot safely be used by multiple threads. In a multi-processing
58  * environment, each thread should use a thread-specific ExponentialProb
59  * object.
60  **********************************************************************/
62  private:
63  typedef unsigned word;
64  public:
65 
66  ExponentialProb() : _v(std::vector<word>(alloc_incr)) {}
67  /**
68  * Return true with probability exp(&minus;\e p). Returns false if \e p
69  * &le; 0. For in \e p (0,1], it requires about exp(\e p) random deviates.
70  * For \e p large, it requires about exp(1)/(1 &minus; exp(&minus;1))
71  * random deviates.
72  *
73  * @tparam RealType the real type of the argument.
74  * @tparam Random the type of the random generator.
75  * @param[in,out] r a random generator.
76  * @param[in] p the probability.
77  * @return true with probability \e p.
78  **********************************************************************/
79  template<typename RealType, class Random>
80  bool operator()(Random& r, RealType p) const;
81 
82  private:
83  /**
84  * Return true with probability exp(&minus;\e p) for \e p in [0,1].
85  **********************************************************************/
86  template<typename RealType, class Random>
87  bool ExpFraction(Random& r, RealType p) const;
88  /**
89  * Holds as much of intermediate uniform deviates as needed.
90  **********************************************************************/
91  mutable std::vector<word> _v;
92  /**
93  * Increment on size of _v.
94  **********************************************************************/
95  static const unsigned alloc_incr = 16;
96  };
97 
98  template<typename RealType, class Random>
99  bool ExponentialProb::operator()(Random& r, RealType p) const {
100  STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer,
101  "ExponentialProb(): invalid real type RealType");
102  return p <= 0 || // True if p <=0
103  // Ensure p - 1 < p. Also deal with IsNaN(p)
104  ( p < RealType(1)/std::numeric_limits<RealType>::epsilon() &&
105  // exp(a+b) = exp(a) * exp(b)
106  ExpFraction(r, p < RealType(1) ? p : RealType(1)) &&
107  ( p <= RealType(1) || operator()(r, p - RealType(1)) ) );
108  }
109 
110  template<typename RealType, class Random>
111  bool ExponentialProb::ExpFraction(Random& r, RealType p) const {
112  // Base of _v is 2^c. Adjust so that word(p) doesn't lose precision.
113  static const int c = // The Intel compiler needs this to be static??
114  std::numeric_limits<word>::digits <
115  std::numeric_limits<RealType>::digits ?
116  std::numeric_limits<word>::digits :
117  std::numeric_limits<RealType>::digits;
118  // m gives number of valid words in _v
119  unsigned m = 0, l = unsigned(_v.size());
120  if (p < RealType(1))
121  while (true) {
122  if (p <= RealType(0))
123  return true;
124  // p in (0, 1)
125  if (l == m)
126  _v.resize(l += alloc_incr);
127  _v[m++] = r.template Integer<word, c>();
128  p *= std::pow(RealType(2), c); // p in (0, 2^c)
129  word w = word(p); // w in [0, 2^c)
130  if (_v[m - 1] > w)
131  return true;
132  else if (_v[m - 1] < w)
133  break;
134  else // _v[m - 1] == w
135  p -= RealType(w); // p in [0, 1)
136  }
137  // Here _v < p. Now loop finding decreasing V. Exit when first increasing
138  // one is found.
139  for (unsigned s = 0; ; s ^= 1) { // Parity of loop count
140  for (unsigned j = 0; ; ++j) {
141  if (j == m) {
142  // Need more bits in the old V
143  if (l == m)
144  _v.resize(l += alloc_incr);
145  _v[m++] = r.template Integer<word, c>();
146  }
147  word w = r.template Integer<word, c>();
148  if (w > _v[j])
149  return s != 0u; // New V is bigger, so exit
150  else if (w < _v[j]) {
151  _v[j] = w; // New V is smaller, update _v
152  m = j + 1; // adjusting its size
153  break; // and generate the next V
154  }
155  // Else w == _v[j] and we need to check the next c bits
156  }
157  }
158  }
159 
160 } // namespace RandomLib
161 
162 #if defined(_MSC_VER)
163 # pragma warning (pop)
164 #endif
165 
166 #endif // RANDOMLIB_EXPONENTIALPROB_HPP
The exponential probability.
Generate random integers, reals, and booleans.
#define STATIC_ASSERT(cond, reason)
Definition: MPFRRandom.hpp:31
bool operator()(Random &r, RealType p) const