RandomLib  1.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
MPFRNormal.hpp
Go to the documentation of this file.
1 /**
2  * \file MPFRNormal.hpp
3  * \brief Header for MPFRNormal
4  *
5  * Sampling exactly from the normal distribution for MPFR.
6  *
7  * Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
8  * the MIT/X11 License. For more information, see
9  * http://randomlib.sourceforge.net/
10  **********************************************************************/
11 
12 #if !defined(RANDOMLIB_MPFRNORMAL_HPP)
13 #define RANDOMLIB_MPFRNORMAL_HPP 1
14 
15 #include <algorithm> // for max/min
16 #include <RandomLib/MPFRRandom.hpp>
17 
18 #if HAVE_MPFR || defined(DOXYGEN)
19 
20 namespace RandomLib {
21 
22  /**
23  * \brief The normal distribution for MPFR.
24  *
25  * This is a transcription of ExactNormal (version 1.3) for use with MPFR.
26  *
27  * This class uses mutable private objects. So a single MPFRNormal object
28  * cannot safely be used by multiple threads. In a multi-processing
29  * environment, each thread should use a thread-specific MPFRNormal object.
30  *
31  * @tparam bits the number of bits in each digit.
32  **********************************************************************/
33  template<int bits = 32> class MPFRNormal {
34  public:
35 
36  /**
37  * Initialize the MPFRNormal object.
38  **********************************************************************/
39  MPFRNormal() { mpz_init(_tt); }
40  /**
41  * Destroy the MPFRNormal object.
42  **********************************************************************/
43  ~MPFRNormal() { mpz_clear(_tt); }
44  /**
45  * Sample from the normal distribution with mean 0 and variance 1 returning
46  * a MPFRRandom.
47  *
48  * @param[out] t the MPFRRandom result.
49  * @param[in,out] r a GMP random generator.
50  **********************************************************************/
51  void operator()(MPFRRandom<bits>& t,gmp_randstate_t r) const
52  { Compute(r); return _x.swap(t); }
53  /**
54  * Sample from the normal distribution with mean 0 and variance 1.
55  *
56  * @param[out] val the sample from the normal distribution
57  * @param[in,out] r a GMP random generator.
58  * @param[in] round the rounding direction.
59  * @return the MPFR ternary result (&plusmn;1 if val is larger/smaller than
60  * the exact sample).
61  **********************************************************************/
62  int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
63  { Compute(r); return _x(val, r, round); }
64  private:
65  // Disable copy constructor and assignment operator
66  MPFRNormal(const MPFRNormal&);
67  MPFRNormal& operator=(const MPFRNormal&);
68  // True with prob exp(-1/2)
69  int ExpProbH(gmp_randstate_t r) const {
70  _p.Init(); if (_p.TestHighBit(r)) return 1;
71  // von Neumann rejection
72  while (true) {
73  _q.Init(); if (!_q.LessThan(r, _p)) return 0;
74  _p.Init(); if (!_p.LessThan(r, _q)) return 1;
75  }
76  }
77  // True with prob exp(-n/2)
78  int ExpProb(gmp_randstate_t r, unsigned n) const {
79  while (n--) { if (!ExpProbH(r)) return 0; }
80  return 1;
81  }
82  // n with prob (1-exp(-1/2)) * exp(-n/2)
83  unsigned ExpProbN(gmp_randstate_t r) const {
84  unsigned n = 0;
85  while (ExpProbH(r)) ++n;
86  return n;
87  }
88  // Return:
89  // 1 with prob 2k/(2k + 2)
90  // 0 with prob 1/(2k + 2)
91  // -1 with prob 1/(2k + 2)
92  int Choose(gmp_randstate_t r, int k) const {
93  const int b = 15; // To avoid integer overflow on multiplication
94  const int m = 2 * k + 2;
95  int n1 = m - 2, n2 = m - 1;
96  while (true) {
97  mpz_urandomb(_tt, r, b);
98  int d = int( mpz_get_ui(_tt) ) * m;
99  n1 = (std::max)((n1 << b) - d, 0);
100  if (n1 >= m) return 1;
101  n2 = (std::min)((n2 << b) - d, m);
102  if (n2 <= 0) return -1;
103  if (n1 == 0 && n2 == m) return 0;
104  }
105  }
106  void Compute(gmp_randstate_t r) const {
107  while (true) {
108  unsigned k = ExpProbN(r); // the integer part of the result.
109  if (ExpProb(r, (k - 1) * k)) {
110  _x.Init();
111  unsigned s = 1;
112  for (unsigned j = 0; j <= k; ++j) { // execute k + 1 times
113  bool first;
114  for (s = 1, first = true; ; s ^= 1, first = false) {
115  if (k == 0 && _x.Boolean(r)) break;
116  _q.Init(); if (!_q.LessThan(r, first ? _x : _p)) break;
117  int y = k == 0 ? 0 : Choose(r, k);
118  if (y < 0)
119  break;
120  else if (y == 0) {
121  _p.Init(); if (!_p.LessThan(r, _x)) break;
122  }
123  _p.swap(_q); // a fast way of doing p = q
124  }
125  if (s == 0) break;
126  }
127  if (s != 0) {
128  _x.AddInteger(k);
129  if (_x.Boolean(r)) _x.Negate();
130  return;
131  }
132  }
133  }
134  }
135  mutable mpz_t _tt; // A temporary
136  mutable MPFRRandom<bits> _x;
137  mutable MPFRRandom<bits> _p;
138  mutable MPFRRandom<bits> _q;
139  };
140 
141 } // namespace RandomLib
142 
143 #endif // HAVE_MPFR
144 #endif // RANDOMLIB_MPFRNORMAL_HPP
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
Definition: MPFRNormal.hpp:62
void operator()(MPFRRandom< bits > &t, gmp_randstate_t r) const
Definition: MPFRNormal.hpp:51
Handling random numbers in MPFR.
Definition: MPFRRandom.hpp:52
Header for MPFRRandom.
The normal distribution for MPFR.
Definition: MPFRNormal.hpp:33