From c64503fb331093250784f6d8f77a804dd61b6c78 Mon Sep 17 00:00:00 2001 From: Alexandre Duret-Lutz Date: Wed, 18 Dec 2013 23:42:25 +0100 Subject: [PATCH] c++11: Simplify random generation code using C++11. * src/misc/random.cc, src/misc/random.hh (srand, drand, mrand, rrand, barand): Simplify using from C++11. (nrand, bmrand, prand): Remove these unused functions. * src/tgbaalgos/randomgraph.cc: Adjust the use of barand. * configure.ac: Do not check for srand48 and drand48. --- configure.ac | 2 +- src/misc/random.cc | 102 +++++------------------------------ src/misc/random.hh | 59 ++------------------ src/tgbaalgos/randomgraph.cc | 2 +- 4 files changed, 18 insertions(+), 147 deletions(-) diff --git a/configure.ac b/configure.ac index 939d66105..d296b0aa6 100644 --- a/configure.ac +++ b/configure.ac @@ -110,7 +110,7 @@ AX_CHECK_BUDDY AX_CHECK_GSPNLIB AC_CHECK_HEADERS([sys/times.h]) -AC_CHECK_FUNCS([times srand48 drand48 kill alarm]) +AC_CHECK_FUNCS([times kill alarm]) LT_CONFIG_LTDL_DIR([ltdl]) LT_INIT([win32-dll]) diff --git a/src/misc/random.cc b/src/misc/random.cc index 49e8f6b67..2c62413b7 100644 --- a/src/misc/random.cc +++ b/src/misc/random.cc @@ -21,121 +21,43 @@ // along with this program. If not, see . #include "config.h" -#include "_config.h" #include "random.hh" -#include namespace spot { + std::mt19937 gen; + void srand(unsigned int seed) { -#if SPOT_HAVE_SRAND48 && SPOT_HAVE_DRAND48 - ::srand48(seed); -#else - ::srand(seed); -#endif + gen.seed(seed); } double drand() { -#if SPOT_HAVE_SRAND48 && SPOT_HAVE_DRAND48 - return ::drand48(); -#else - double r = ::rand(); - return r / (1.0 + RAND_MAX); -#endif + return + std::generate_canonical::digits>(gen); } int mrand(int max) { - return static_cast(max * drand()); + std::uniform_int_distribution<> dis(0, max - 1); + return dis(gen); } int rrand(int min, int max) { - return min + static_cast((max - min + 1) * drand()); - } - - double - nrand() - { - const double r = drand(); - - const double lim = 1.e-20; - if (r < lim) - return -1./lim; - if (r > 1.0 - lim) - return 1./lim; - - double t; - if (r < 0.5) - t = sqrt(-2.0 * log(r)); - else - t = sqrt(-2.0 * log(1.0 - r)); - - const double p0 = 0.322232431088; - const double p1 = 1.0; - const double p2 = 0.342242088547; - const double p3 = 0.204231210245e-1; - const double p4 = 0.453642210148e-4; - const double q0 = 0.099348462606; - const double q1 = 0.588581570495; - const double q2 = 0.531103462366; - const double q3 = 0.103537752850; - const double q4 = 0.385607006340e-2; - const double p = p0 + t * (p1 + t * (p2 + t * (p3 + t * p4))); - const double q = q0 + t * (q1 + t * (q2 + t * (q3 + t * q4))); - - if (r < 0.5) - return (p / q) - t; - else - return t - (p / q); - } - - double - bmrand() - { - static double next; - static bool has_next = false; - - if (has_next) - { - has_next = false; - return next; - } - - double x; - double y; - double r; - do - { - x = 2.0 * drand() - 1.0; - y = 2.0 * drand() - 1.0; - r = x * x + y * y; - } - while (r >= 1.0 || r == 0.0); - r = sqrt(-2 * log(r) / r); - next = y * r; - has_next = true; - return x * r; + std::uniform_int_distribution<> dis(min, max); + return dis(gen); } int - prand(double p) + barand::rand() { - double s = 0.0; - long x = 0; - - while (s < p) - { - s -= log(1.0 - drand()); - ++x; - } - return x - 1; + return (*this)(gen); } - } diff --git a/src/misc/random.hh b/src/misc/random.hh index e365899c2..d64ac194a 100644 --- a/src/misc/random.hh +++ b/src/misc/random.hh @@ -24,7 +24,7 @@ # define SPOT_MISC_RANDOM_HH # include "common.hh" -# include +# include namespace spot { @@ -55,69 +55,18 @@ namespace spot /// \see mrand, rrand, srand SPOT_API double drand(); - /// \brief Compute a pseudo-random double value - /// following a standard normal distribution. (Odeh & Evans) - /// - /// This uses a polynomial approximation of the inverse cumulated - /// density function from Odeh & Evans, Journal of Applied - /// Statistics, 1974, vol 23, pp 96-97. - SPOT_API double nrand(); - - /// \brief Compute a pseudo-random double value - /// following a standard normal distribution. (Box-Muller) - /// - /// This uses the polar form of the Box-Muller transform - /// to generate random values. - SPOT_API double bmrand(); - /// \brief Compute pseudo-random integer value between 0 /// and \a n included, following a binomial distribution /// for probability \a p. - /// - /// \a gen must be a random function computing a pseudo-random - /// double value following a standard normal distribution. - /// Use nrand() or bmrand(). - /// - /// Usually approximating a binomial distribution using a normal - /// distribution and is accurate only if n*p and - /// n*(1-p) are greater than 5. - template - class barand + class SPOT_API barand : protected std::binomial_distribution<> { public: - barand(int n, double p) - : n_(n), m_(n * p), s_(sqrt(n * p * (1 - p))) + barand(int n, double p) : binomial_distribution(n, p) { } - int - rand() const - { - int res; - - for (;;) - { - double x = gen() * s_ + m_; - if (x < 0.0) - continue; - res = static_cast (x); - if (res <= n_) - break; - } - return res; - } - protected: - const int n_; - const double m_; - const double s_; + int rand(); }; - - /// \brief Return a pseudo-random positive integer value - /// following a Poisson distribution with parameter \a p. - /// - /// \pre p > 0 - SPOT_API int prand(double p); - /// @} } #endif // SPOT_MISC_RANDOM_HH diff --git a/src/tgbaalgos/randomgraph.cc b/src/tgbaalgos/randomgraph.cc index b05807e60..220321ec2 100644 --- a/src/tgbaalgos/randomgraph.cc +++ b/src/tgbaalgos/randomgraph.cc @@ -149,7 +149,7 @@ namespace spot // We want to connect each node to a number of successors between // 1 and n. If the probability to connect to each successor is d, // the number of connected successors follows a binomial distribution. - barand bin(n - 1, d); + barand bin(n - 1, d); while (!nodes_to_process.empty()) {