RandomLib  1.10
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Macros Pages
MPFRExponentialL.hpp
Go to the documentation of this file.
1 /**
2  * \file MPFRExponentialL.hpp
3  * \brief Header for MPFRExponentialL
4  *
5  * Sampling exactly from the exponential distribution for MPFR using the
6  * traditional method.
7  *
8  * Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
9  * the MIT/X11 License. For more information, see
10  * http://randomlib.sourceforge.net/
11  **********************************************************************/
12 
13 #if !defined(RANDOMLIB_MPFREXPONENTIALL_HPP)
14 #define RANDOMLIB_MPFREXPONENTIALL_HPP 1
15 
16 #include <cmath> // for log
17 #include <mpfr.h>
18 
19 #define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3)
20 
21 #if HAVE_MPFR || defined(DOXYGEN)
22 
23 namespace RandomLib {
24 
25  /**
26  * \brief The exponential distribution for MPFR (the log method).
27  *
28  * This class is <b>DEPRECATED</b>. It is included for illustrative purposes
29  * only. The MPFRExponential class provides a much more efficient method for
30  * sampling from the exponential distribution.
31  *
32  * This is an adaption of ExponentialDistribution to MPFR. The changes are
33  * - Use MPFR's random number generator
34  * - Use sufficient precision internally to ensure that a correctly rounded
35  * result is returned.
36  *
37  * This class uses mutable private objects. So a single MPFRExponentialL
38  * object cannot safely be used by multiple threads. In a multi-processing
39  * environment, each thread should use a thread-specific MPFRExponentialL
40  * object.
41  **********************************************************************/
43  private:
44  // The number of bits of randomness to add at a time.
45  static const long chunk_ = 32;
46 
47  public:
48  /**
49  * Initialize the MPFRExponentialL object.
50  **********************************************************************/
52  mpz_init(_vi);
53  mpfr_init2(_eps, chunk_);
54  mpfr_init2(_v1, chunk_);
55  mpfr_init2(_v2, chunk_);
56  }
57  /**
58  * Destroy the MPFRExponentialL object.
59  **********************************************************************/
61  mpfr_clear(_v2);
62  mpfr_clear(_v1);
63  mpfr_clear(_eps);
64  mpz_clear(_vi);
65  }
66  /**
67  * Sample from the exponential distribution with mean 1.
68  *
69  * @param[out] val the sample from the exponential distribution
70  * @param[in,out] r a GMP random generator.
71  * @param[in] round the rounding direction.
72  * @return the MPFR ternary result (&plusmn; if val is larger/smaller than
73  * the exact sample).
74  **********************************************************************/
75  int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const {
76 
77  mpfr_prec_t prec0 = mpfr_get_prec (val);
78  mpfr_prec_t prec = prec0 + 10; // A rough optimum
79  mpz_urandomb(_vi, r, prec);
80  mpfr_set_ui_2exp(_eps, 1u, -prec, MPFR_RNDN);
81  mpfr_set_prec(_v1, prec);
82  mpfr_set_z_2exp(_v1, _vi, -prec, MPFR_RNDN);
83  mpfr_set_prec(_v2, prec);
84  mpfr_add(_v2, _v1, _eps, MPFR_RNDN);
85  while (true) {
86  int f2 = mpfr_log(val, _v2, round); // val = log(upper bound)
87  mpfr_set_prec(_v2, prec0);
88  int f1 = mpfr_log(_v2, _v1, round); // v2 = log(lower bound)
89  if (f1 == f2 && mpfr_equal_p(val, _v2)) {
90  mpfr_neg(val, val, MPFR_RNDN);
91  return -f1;
92  }
93  prec = Refine(r, prec);
94  }
95  }
96  private:
97  // disable copy constructor and assignment operator
99  MPFRExponentialL& operator=(const MPFRExponentialL&);
100  // Refine the random interval
101  mpfr_prec_t Refine(gmp_randstate_t r, mpfr_prec_t prec)
102  const {
103  prec += chunk_;
104  mpfr_div_2ui(_eps, _eps, chunk_, MPFR_RNDN);
105  mpz_urandomb(_vi, r, chunk_);
106  mpfr_set_prec(_v2, prec);
107  mpfr_set_z_2exp(_v2, _vi, -prec, MPFR_RNDN);
108  mpfr_add(_v2, _v1, _v2, MPFR_RNDN);
109  mpfr_swap(_v1, _v2); // v1 = v2;
110  mpfr_set_prec(_v2, prec);
111  mpfr_add(_v2, _v1, _eps, MPFR_RNDN);
112  return prec;
113  }
114  mutable mpz_t _vi;
115  mutable mpfr_t _eps;
116  mutable mpfr_t _v1;
117  mutable mpfr_t _v2;
118  };
119 
120 } // namespace RandomLib
121 
122 #endif // HAVE_MPFR
123 #endif // RANDOMLIB_MPFREXPONENTIALL_HPP
The exponential distribution for MPFR (the log method).
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const