RandomLib  1.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
MPFRRandom.hpp
Go to the documentation of this file.
1 /**
2  * \file MPFRRandom.hpp
3  * \brief Header for MPFRRandom
4  *
5  * Utility class for MPFRUniform, MPFRExponential, and MPFRNormal.
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_MPFRRANDOM_HPP)
13 #define RANDOMLIB_MPFRRANDOM_HPP 1
14 
15 #include <algorithm> // for swap
16 #include <mpfr.h>
17 
18 #define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3)
19 
20 #if HAVE_MPFR || defined(DOXYGEN)
21 
22 /**
23  * A compile-time assert. Use C++11 static_assert, if available.
24  **********************************************************************/
25 #if !defined(STATIC_ASSERT)
26 # if defined(__GXX_EXPERIMENTAL_CXX0X__)
27 # define STATIC_ASSERT static_assert
28 # elif defined(_MSC_VER) && _MSC_VER >= 1600
29 # define STATIC_ASSERT static_assert
30 # else
31 # define STATIC_ASSERT(cond,reason) \
32  { enum{ STATIC_ASSERT_ENUM = 1/int(cond) }; }
33 # endif
34 #endif
35 
36 namespace RandomLib {
37 
38  /**
39  * \brief Handling random numbers in MPFR.
40  *
41  * This class provides roughly the same capabilities as RandomNumber. The
42  * fraction is represented by a mpz integer \e f and an exponent \e e. We
43  * have \e e &ge; 0 and 0 &le; \e f < <i>b</i><sup><i>e</i></sup>, and \e b =
44  * 2<sup><i>bits</i></sup>. This represents the number \e x = \e f
45  * <i>b</i><sup>&minus;<i>e</i></sup>, with x in [0, 1).
46  *
47  * @tparam bits the number of bits in each digit.
48  *
49  * \e bits must divide GMP_LIMB_BITS. The default value \e bits = 32 yields
50  * portable results on all MPFR platforms.
51  **********************************************************************/
52  template<int bits = 32> class MPFRRandom {
53  private:
54  static const int limb_ = GMP_LIMB_BITS; // How many bits in a limb
55  static const int loglimb_ = (limb_ == 32 ? 5 :
56  (limb_ == 64 ? 6 :
57  (limb_ == 128 ? 7 : -1)));
58  static const int logbits_ = (bits == 1 ? 0 :
59  (bits == 2 ? 1 :
60  (bits == 4 ? 2 :
61  (bits == 8 ? 3 :
62  (bits == 16 ? 4 :
63  (bits == 32 ? 5 :
64  (bits == 64 ? 6 :
65  (bits == 128 ? 7 : -1))))))));
66  static const mp_limb_t mask_ = (bits == limb_ ? ~0UL : // Digit mask
67  ~(~0UL << (bits < limb_ ? bits : 0)));
68  static const int logw_ = loglimb_ - logbits_; // 2^logw digits per limb
69  static const unsigned wmask_ = ~(~0U << logw_);
70 
71  mutable mpz_t _tt; // A temporary
72  mpz_t _f; // The fraction
73  mp_size_t _e; // Count of digits
74  unsigned long _n; // Integer part
75  int _s; // Sign
76  void AddDigits(gmp_randstate_t r, long num = 1) { // Add num more digits
77  if (num <= 0) return;
78  mpz_mul_2exp(_f, _f, num << logbits_);
79  mpz_urandomb(_tt, r, num << logbits_);
80  mpz_add(_f, _f, _tt);
81  _e += num;
82  }
83  // return k'th digit counting k = 0 as most significant
84  mp_limb_t Digit(gmp_randstate_t r, mp_size_t k) {
85  ExpandTo(r, k); // Now e > k
86  k = _e - 1 - k; // Reverse k so k = 0 is least significant
87  // (k >> logw) is the limb index
88  // (k & wmask) is the digit position within the limb
89  return mask_ &
90  (mpz_getlimbn(_f, k >> logw_) >> ((k & wmask_) << logbits_));
91  }
92  // Return index [0..32] of highest bit set. Return 0 if x = 0, 32 is if x
93  // = ~0. (From Algorithms for programmers by Joerg Arndt.)
94  static int highest_bit_idx(unsigned long x) throw() {
95  if (x == 0) return 0;
96  int r = 1;
97  // STILL TO DO: handle 64-bit unsigned longs.
98  if (x & 0xffff0000UL) { x >>= 16; r += 16; }
99  if (x & 0x0000ff00UL) { x >>= 8; r += 8; }
100  if (x & 0x000000f0UL) { x >>= 4; r += 4; }
101  if (x & 0x0000000cUL) { x >>= 2; r += 2; }
102  if (x & 0x00000002UL) { r += 1; }
103  return r;
104  }
105  public:
106  /**
107  * Initialize the MPFRRandom object.
108  **********************************************************************/
109  MPFRRandom() : _e(0u), _n(0u), _s(1) {
110  STATIC_ASSERT(logbits_ >= 0 && loglimb_ >= 0 && logbits_ <= loglimb_,
111  "MPRFRandom: unsupported value for bits");
112  mpz_init(_f); mpz_init(_tt);
113  }
114  /**
115  * Initialize the MPFRRandom object from another one.
116  *
117  * @param[in] t the MPFRRandom to copy.
118  **********************************************************************/
119  MPFRRandom(const MPFRRandom& t) : _e(t._e), _n(t._n), _s(t._s)
120  { mpz_init(_f); mpz_set(_f, t._f); mpz_init(_tt); }
121  /**
122  * Destroy the MPFRRandom object.
123  **********************************************************************/
124  ~MPFRRandom() { mpz_clear(_f); mpz_clear(_tt); }
125  /**
126  * Assignment operator. (But swapping is typically faster.)
127  *
128  * @param[in] t the MPFRRandom to copy.
129  **********************************************************************/
131  _e = t._e;
132  _n = t._n;
133  _s = t._s;
134  mpz_set(_f, t._f); // Don't copy _tt
135  return *this;
136  }
137  /**
138  * Swap with another MPFRRandom. This is a fast way of doing an
139  * assignment.
140  *
141  * @param[in,out] t the MPFRRandom to swap with.
142  **********************************************************************/
143  void swap(MPFRRandom& t) throw() {
144  if (this != &t) {
145  std::swap(_e, t._e);
146  std::swap(_n, t._n);
147  std::swap(_s, t._s);
148  mpz_swap(_f, t._f); // Don't swap _tt
149  }
150  }
151  /**
152  * Reinitialize the MPFRRandom object, setting its value to [0,1].
153  **********************************************************************/
154  void Init() { mpz_set_ui(_f, 0u); _e = 0; _n = 0; _s = 1; }
155  /**
156  * @return the sign of the MPFRRandom (&plusmn; 1).
157  **********************************************************************/
158  int Sign() const throw() { return _s; }
159  /**
160  * Change the sign of the MPFRRandom.
161  **********************************************************************/
162  void Negate() throw() { _s *= -1; }
163  /**
164  * @return the floor of the MPFRRandom
165  **********************************************************************/
166  long Floor() const throw() { return _s > 0 ? long(_n) : -1 - long(_n); }
167  /**
168  * @return the ceiling of the MPFRRandom
169  **********************************************************************/
170  long Ceiling() const throw() { return _s > 0 ? 1 + long(_n) : -long(_n); }
171  /**
172  * @return the unsigned integer component of the MPFRRandom.
173  **********************************************************************/
174  unsigned long UInteger() const throw() { return _n; }
175  /**
176  * @return the number of digits in fraction
177  **********************************************************************/
178  unsigned long Size() const throw() { return unsigned(_e); }
179  /**
180  * Add integer \e k to the MPRFRandom.
181  *
182  * @param[in] k the integer to add.
183  **********************************************************************/
184  void AddInteger(long k) {
185  k += Floor(); // The new floor
186  int ns = k < 0 ? -1 : 1; // The new sign
187  if (ns != _s) { // If sign changes, set f = 1 - f
188  mpz_set_ui(_tt, 1u);
189  mpz_mul_2exp(_tt, _tt, _e << logbits_);
190  mpz_sub_ui(_tt, _tt, 1u);
191  mpz_sub(_f, _tt, _f);
192  _s = ns;
193  }
194  _n = ns > 0 ? k : -(k + 1);
195  }
196  /**
197  * Compare with another MPFRRandom, *this < \e t.
198  *
199  * @param[in,out] r a random generator.
200  * @param[in,out] t a MPFRRandom to compare.
201  * @return true if *this < \e t.
202  **********************************************************************/
203  int LessThan(gmp_randstate_t r, MPFRRandom& t) {
204  if (this == &t) return false; // same object
205  if (_s != t._s) return _s < t._s;
206  if (_n != t._n) return (_s < 0) ^ (_n < t._n);
207  for (mp_size_t k = 0; ; ++k) {
208  mp_limb_t x = Digit(r, k);
209  mp_limb_t y = t.Digit(r, k);
210  if (x != y) return (_s < 0) ^ (x < y);
211  }
212  }
213  /**
214  * Set high bit of fraction to 1.
215  *
216  * @param[in,out] r a random generator.
217  **********************************************************************/
218  void SetHighBit(gmp_randstate_t r) { // Set the msb to 1
219  ExpandTo(r, 0); // Generate msb if necessary
220  mpz_setbit(_f, (_e << logbits_) - 1);
221  }
222  /**
223  * Test high bit of fraction.
224  *
225  * @param[in,out] r a random generator.
226  **********************************************************************/
227  int TestHighBit(gmp_randstate_t r) { // test the msb of f
228  ExpandTo(r, 0); // Generate msb if necessary
229  return mpz_tstbit(_f, (_e << logbits_) - 1);
230  }
231  /**
232  * Return the position of the most significant bit in the MPFRRandom.
233  *
234  * @param[in,out] r a random generator.
235  *
236  * The bit position is numbered such the 1/2 bit is 0, the 1/4 bit is -1,
237  * etc.
238  **********************************************************************/
239  mp_size_t LeadingBit(gmp_randstate_t r) {
240  if (_n) return highest_bit_idx(_n);
241  while (true) {
242  int sgn = mpz_sgn(_f);
243  if (sgn != 0)
244  return mp_size_t(mpz_sizeinbase(_f, 2)) - mp_size_t(_e << logbits_);
245  AddDigits(r);
246  }
247  }
248  /**
249  * Ensure that the k'th digit of the fraction is computed.
250  *
251  * @param[in,out] r a random generator.
252  * @param[in] k the digit number (0 is the most significant, 1 is the next
253  * most significant, etc.
254  **********************************************************************/
255  void ExpandTo(gmp_randstate_t r, mp_size_t k)
256  { if (_e <= k) AddDigits(r, k - _e + 1); }
257  /**
258  * Convert to a MPFR number \e without adding more bits.
259  *
260  * @param[out] val the value of s * (n + *this).
261  * @param[in] round the rounding direction.
262  * @return the MPFR ternary result (&plusmn; if val is larger/smaller than
263  * the exact sample).
264  *
265  * If round is MPFR_RNDN, then the rounded midpoint of the interval
266  * represented by the MPFRRandom is returned. Otherwise it is the rounded
267  * lower or upper bound of the interval (whichever is appropriate).
268  **********************************************************************/
269  int operator()(mpfr_t val, mpfr_rnd_t round)
270  { return operator()(val, NULL, round); }
271  /**
272  * Convert to a MPFR number.
273  *
274  * @param[out] val the value of s * (n + *this).
275  * @param[in,out] r a GMP random generator.
276  * @param[in] round the rounding direction.
277  * @return the MPFR ternary result (&plusmn; if val is larger/smaller than
278  * the exact sample).
279  *
280  * If \e r is NULL, then no additional random bits are generated and the
281  * lower bound, midpoint, or upper bound of the MPFRRandom interval is
282  * returned, depending on the value of \e round.
283  **********************************************************************/
284  int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) {
285  // The value is constructed as a positive quantity, so adjust rounding
286  // mode to account for this.
287  switch (round) {
288  case MPFR_RNDD:
289  case MPFR_RNDU:
290  case MPFR_RNDN:
291  break;
292  case MPFR_RNDZ:
293  round = _s < 0 ? MPFR_RNDU : MPFR_RNDD;
294  break;
295  case MPFR_RNDA:
296  round = _s < 0 ? MPFR_RNDD : MPFR_RNDU;
297  break;
298  default:
299  round = MPFR_RNDN; // New rounding modes are variants of N
300  break;
301  } // Now round is one of MPFR_RND{D,N,U}
302 
303  mp_size_t excess;
304  mpfr_exp_t expt;
305  if (r == NULL) {
306  // If r is NULL then all the bits currently generated are considered
307  // significant. Thus no excess bits need to be squeezed out.
308  excess = 0;
309  // And the exponent shift in mpfr_set_z_2exp is just...
310  expt = -(_e << logbits_);
311  // However, if rounding to nearest, we need to make room for the
312  // midpoint bit.
313  if (round == MPFR_RNDN) {
314  excess = -1;
315  --expt;
316  }
317  } else { // r is non-NULL
318  // Generate enough digits, i.e., enough to generate prec significant
319  // figures for RNDD and RNDU; for RNDN we need to generate an
320  // additional guard bit.
321  mp_size_t lead = LeadingBit(r);
322  mpfr_prec_t prec = mpfr_get_prec (val);
323  mp_size_t trail = lead - prec; // position one past trailing bit
324  mp_size_t guard = trail + (round == MPFR_RNDN ? 0 : 1); // guard bit pos
325  // Generate the bits needed.
326  if (guard <= 0) ExpandTo(r, (-guard) >> logbits_);
327  // Unless bits = 1, the generation process will typically have
328  // generated too many bits. We figure out how many, but leaving room
329  // for one additional "inexact" bit. The inexact bit is set to 1 in
330  // order to force MPFR to treat the result as inexact, to break RNDN
331  // ties, and to get the ternary value set correctly.
332  //
333  // expt is the exponent used when forming the number using
334  // mpfr_set_z_2exp. Without the inexact bit, it's (guard - 1).
335  // Subtract 1 to account for the inexact bit.
336  expt = guard - 2;
337  // The number of excess bits is now the difference between the number
338  // of bits in the fraction (e << logbits) and -expt. Note that this
339  // may be -1 (meaning we'll need to shift the number left to
340  // accommodate the inexact bit).
341  excess = (_e << logbits_) + expt;
342  }
343  mpz_set_ui(_tt, _n); // The integer part
344  mpz_mul_2exp(_tt, _tt, _e << logbits_); // Shift to allow for fraction
345  mpz_add(_tt, _tt, _f); // Add fraction
346  if (excess > 0)
347  mpz_tdiv_q_2exp(_tt, _tt, excess);
348  else if (excess < 0)
349  mpz_mul_2exp(_tt, _tt, -excess);
350  if (r || round == MPFR_RNDN)
351  // Set the inexact bit (or compute the midpoint if r is NULL).
352  mpz_setbit(_tt, 0);
353  else if (round == MPFR_RNDU)
354  // If r is NULL, compute the upper bound.
355  mpz_add_ui(_tt, _tt, 1u);
356 
357  // Convert to a mpfr number. If r is specified, then there are
358  // sufficient bits in tt that the result is inexact and that (in the case
359  // of RNDN) there are no ties.
360  int flag = mpfr_set_z_2exp(val, _tt, expt, round);
361  if (_s < 0) {
362  mpfr_neg (val, val, MPFR_RNDN);
363  flag = -flag;
364  }
365  return flag;
366  }
367  /**
368  * A coin toss. (This should really be a static function. But it uses the
369  * MPFRRandom temporary variable.)
370  *
371  * @param[in,out] r a GMP random generator.
372  * @return true or false.
373  **********************************************************************/
374  int Boolean(gmp_randstate_t r) const {
375  mpz_urandomb(_tt, r, 1);
376  return mpz_tstbit(_tt, 0);
377  }
378  };
379 
380 } // namespace RandomLib
381 
382 #endif // HAVE_MPFR
383 #endif // RANDOMLIB_MPFRRANDOM_HPP
void ExpandTo(gmp_randstate_t r, mp_size_t k)
Definition: MPFRRandom.hpp:255
unsigned long Size() const
Definition: MPFRRandom.hpp:178
int TestHighBit(gmp_randstate_t r)
Definition: MPFRRandom.hpp:227
MPFRRandom & operator=(const MPFRRandom &t)
Definition: MPFRRandom.hpp:130
unsigned long UInteger() const
Definition: MPFRRandom.hpp:174
void AddInteger(long k)
Definition: MPFRRandom.hpp:184
long Ceiling() const
Definition: MPFRRandom.hpp:170
void swap(MPFRRandom &t)
Definition: MPFRRandom.hpp:143
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round)
Definition: MPFRRandom.hpp:284
#define STATIC_ASSERT(cond, reason)
Definition: MPFRRandom.hpp:31
long Floor() const
Definition: MPFRRandom.hpp:166
int LessThan(gmp_randstate_t r, MPFRRandom &t)
Definition: MPFRRandom.hpp:203
void swap(RandomLib::RandomCanonical< Generator > &r, RandomLib::RandomCanonical< Generator > &s)
MPFRRandom(const MPFRRandom &t)
Definition: MPFRRandom.hpp:119
int operator()(mpfr_t val, mpfr_rnd_t round)
Definition: MPFRRandom.hpp:269
void SetHighBit(gmp_randstate_t r)
Definition: MPFRRandom.hpp:218
int Boolean(gmp_randstate_t r) const
Definition: MPFRRandom.hpp:374
Handling random numbers in MPFR.
Definition: MPFRRandom.hpp:52
mp_size_t LeadingBit(gmp_randstate_t r)
Definition: MPFRRandom.hpp:239