[Lemon-commits] Alpar Juttner: Platform independent Random gener...

Lemon HG hg at lemon.cs.elte.hu
Fri Mar 23 16:14:06 CET 2018


details:   http://lemon.cs.elte.hu/hg/lemon/rev/db1d342a1087
changeset: 1379:db1d342a1087
user:      Alpar Juttner <alpar [at] cs.elte.hu>
date:      Thu Oct 08 13:48:09 2015 +0200
description:
	Platform independent Random generators (#602)

diffstat:

 lemon/random.h      |  1098 ++++++++++++++++++++++++++------------------------
 test/random_test.cc |    28 +
 2 files changed, 602 insertions(+), 524 deletions(-)

diffs (truncated from 1173 to 300 lines):

diff --git a/lemon/random.h b/lemon/random.h
--- a/lemon/random.h
+++ b/lemon/random.h
@@ -296,7 +296,7 @@
 
     template <typename Result, typename Word,
               int rest = std::numeric_limits<Result>::digits, int shift = 0,
-              bool last = rest <= std::numeric_limits<Word>::digits>
+              bool last = (rest <= std::numeric_limits<Word>::digits)>
     struct IntConversion {
       static const int bits = std::numeric_limits<Word>::digits;
 
@@ -465,543 +465,593 @@
       }
     };
 
-  }
+    /// \ingroup misc
+    ///
+    /// \brief Mersenne Twister random number generator
+    ///
+    /// The Mersenne Twister is a twisted generalized feedback
+    /// shift-register generator of Matsumoto and Nishimura. The period
+    /// of this generator is \f$ 2^{19937} - 1 \f$ and it is
+    /// equi-distributed in 623 dimensions for 32-bit numbers. The time
+    /// performance of this generator is comparable to the commonly used
+    /// generators.
+    ///
+    /// This is a template version implementation both 32-bit and
+    /// 64-bit architecture optimized versions. The generators differ
+    /// sligthly in the initialization and generation phase so they
+    /// produce two completly different sequences.
+    ///
+    /// \alert Do not use this class directly, but instead one of \ref
+    /// Random, \ref Random32 or \ref Random64.
+    ///
+    /// The generator gives back random numbers of serveral types. To
+    /// get a random number from a range of a floating point type you
+    /// can use one form of the \c operator() or the \c real() member
+    /// function. If you want to get random number from the {0, 1, ...,
+    /// n-1} integer range use the \c operator[] or the \c integer()
+    /// method. And to get random number from the whole range of an
+    /// integer type you can use the argumentless \c integer() or \c
+    /// uinteger() functions. After all you can get random bool with
+    /// equal chance of true and false or given probability of true
+    /// result with the \c boolean() member functions.
+    ///
+    ///\code
+    /// // The commented code is identical to the other
+    /// double a = rnd();                     // [0.0, 1.0)
+    /// // double a = rnd.real();             // [0.0, 1.0)
+    /// double b = rnd(100.0);                // [0.0, 100.0)
+    /// // double b = rnd.real(100.0);        // [0.0, 100.0)
+    /// double c = rnd(1.0, 2.0);             // [1.0, 2.0)
+    /// // double c = rnd.real(1.0, 2.0);     // [1.0, 2.0)
+    /// int d = rnd[100000];                  // 0..99999
+    /// // int d = rnd.integer(100000);       // 0..99999
+    /// int e = rnd[6] + 1;                   // 1..6
+    /// // int e = rnd.integer(1, 1 + 6);     // 1..6
+    /// int b = rnd.uinteger<int>();          // 0 .. 2^31 - 1
+    /// int c = rnd.integer<int>();           // - 2^31 .. 2^31 - 1
+    /// bool g = rnd.boolean();               // P(g = true) = 0.5
+    /// bool h = rnd.boolean(0.8);            // P(h = true) = 0.8
+    ///\endcode
+    ///
+    /// LEMON provides a global instance of the random number
+    /// generator which name is \ref lemon::rnd "rnd". Usually it is a
+    /// good programming convenience to use this global generator to get
+    /// random numbers.
+    ///
+    /// \sa \ref Random, \ref Random32 or \ref Random64.
+    ///
+    template<class Word>
+    class Random {
+    private:
+
+      _random_bits::RandomCore<Word> core;
+      _random_bits::BoolProducer<Word> bool_producer;
+
+
+    public:
+
+      ///\name Initialization
+      ///
+      /// @{
+
+      /// \brief Default constructor
+      ///
+      /// Constructor with constant seeding.
+      Random() { core.initState(); }
+
+      /// \brief Constructor with seed
+      ///
+      /// Constructor with seed. The current number type will be converted
+      /// to the architecture word type.
+      template <typename Number>
+      Random(Number seed) {
+        _random_bits::Initializer<Number, Word>::init(core, seed);
+      }
+
+      /// \brief Constructor with array seeding
+      ///
+      /// Constructor with array seeding. The given range should contain
+      /// any number type and the numbers will be converted to the
+      /// architecture word type.
+      template <typename Iterator>
+      Random(Iterator begin, Iterator end) {
+        typedef typename std::iterator_traits<Iterator>::value_type Number;
+        _random_bits::Initializer<Number, Word>::init(core, begin, end);
+      }
+
+      /// \brief Copy constructor
+      ///
+      /// Copy constructor. The generated sequence will be identical to
+      /// the other sequence. It can be used to save the current state
+      /// of the generator and later use it to generate the same
+      /// sequence.
+      Random(const Random& other) {
+        core.copyState(other.core);
+      }
+
+      /// \brief Assign operator
+      ///
+      /// Assign operator. The generated sequence will be identical to
+      /// the other sequence. It can be used to save the current state
+      /// of the generator and later use it to generate the same
+      /// sequence.
+      Random& operator=(const Random& other) {
+        if (&other != this) {
+          core.copyState(other.core);
+        }
+        return *this;
+      }
+
+      /// \brief Seeding random sequence
+      ///
+      /// Seeding the random sequence. The current number type will be
+      /// converted to the architecture word type.
+      template <typename Number>
+      void seed(Number seed) {
+        _random_bits::Initializer<Number, Word>::init(core, seed);
+      }
+
+      /// \brief Seeding random sequence
+      ///
+      /// Seeding the random sequence. The given range should contain
+      /// any number type and the numbers will be converted to the
+      /// architecture word type.
+      template <typename Iterator>
+      void seed(Iterator begin, Iterator end) {
+        typedef typename std::iterator_traits<Iterator>::value_type Number;
+        _random_bits::Initializer<Number, Word>::init(core, begin, end);
+      }
+
+      /// \brief Seeding from file or from process id and time
+      ///
+      /// By default, this function calls the \c seedFromFile() member
+      /// function with the <tt>/dev/urandom</tt> file. If it does not success,
+      /// it uses the \c seedFromTime().
+      /// \return Currently always \c true.
+      bool seed() {
+#ifndef LEMON_WIN32
+        if (seedFromFile("/dev/urandom", 0)) return true;
+#endif
+        if (seedFromTime()) return true;
+        return false;
+      }
+
+      /// \brief Seeding from file
+      ///
+      /// Seeding the random sequence from file. The linux kernel has two
+      /// devices, <tt>/dev/random</tt> and <tt>/dev/urandom</tt> which
+      /// could give good seed values for pseudo random generators (The
+      /// difference between two devices is that the <tt>random</tt> may
+      /// block the reading operation while the kernel can give good
+      /// source of randomness, while the <tt>urandom</tt> does not
+      /// block the input, but it could give back bytes with worse
+      /// entropy).
+      /// \param file The source file
+      /// \param offset The offset, from the file read.
+      /// \return \c true when the seeding successes.
+#ifndef LEMON_WIN32
+      bool seedFromFile(const std::string& file = "/dev/urandom", int offset = 0)
+#else
+        bool seedFromFile(const std::string& file = "", int offset = 0)
+#endif
+      {
+        std::ifstream rs(file.c_str());
+        const int size = 4;
+        Word buf[size];
+        if (offset != 0 && !rs.seekg(offset)) return false;
+        if (!rs.read(reinterpret_cast<char*>(buf), sizeof(buf))) return false;
+        seed(buf, buf + size);
+        return true;
+      }
+
+      /// \brief Seding from process id and time
+      ///
+      /// Seding from process id and time. This function uses the
+      /// current process id and the current time for initialize the
+      /// random sequence.
+      /// \return Currently always \c true.
+      bool seedFromTime() {
+#ifndef LEMON_WIN32
+        timeval tv;
+        gettimeofday(&tv, 0);
+        seed(getpid() + tv.tv_sec + tv.tv_usec);
+#else
+        seed(bits::getWinRndSeed());
+#endif
+        return true;
+      }
+
+      /// @}
+
+      ///\name Uniform Distributions
+      ///
+      /// @{
+
+      /// \brief Returns a random real number from the range [0, 1)
+      ///
+      /// It returns a random real number from the range [0, 1). The
+      /// default Number type is \c double.
+      template <typename Number>
+      Number real() {
+        return _random_bits::RealConversion<Number, Word>::convert(core);
+      }
+
+      double real() {
+        return real<double>();
+      }
+
+      /// \brief Returns a random real number from the range [0, 1)
+      ///
+      /// It returns a random double from the range [0, 1).
+      double operator()() {
+        return real<double>();
+      }
+
+      /// \brief Returns a random real number from the range [0, b)
+      ///
+      /// It returns a random real number from the range [0, b).
+      double operator()(double b) {
+        return real<double>() * b;
+      }
+
+      /// \brief Returns a random real number from the range [a, b)
+      ///
+      /// It returns a random real number from the range [a, b).
+      double operator()(double a, double b) {
+        return real<double>() * (b - a) + a;
+      }
+
+      /// \brief Returns a random integer from a range
+      ///
+      /// It returns a random integer from the range {0, 1, ..., b - 1}.
+      template <typename Number>
+      Number integer(Number b) {
+        return _random_bits::Mapping<Number, Word>::map(core, b);
+      }
+
+      /// \brief Returns a random integer from a range
+      ///
+      /// It returns a random integer from the range {a, a + 1, ..., b - 1}.
+      template <typename Number>
+      Number integer(Number a, Number b) {
+        return _random_bits::Mapping<Number, Word>::map(core, b - a) + a;
+      }
+
+      /// \brief Returns a random integer from a range
+      ///
+      /// It returns a random integer from the range {0, 1, ..., b - 1}.
+      template <typename Number>
+      Number operator[](Number b) {
+        return _random_bits::Mapping<Number, Word>::map(core, b);
+      }
+
+      /// \brief Returns a random non-negative integer
+      ///
+      /// It returns a random non-negative integer uniformly from the
+      /// whole range of the current \c Number type. The default result
+      /// type of this function is <tt>unsigned int</tt>.
+      template <typename Number>
+      Number uinteger() {
+        return _random_bits::IntConversion<Number, Word>::convert(core);
+      }
+
+      unsigned int uinteger() {
+        return uinteger<unsigned int>();
+      }
+
+      /// \brief Returns a random integer
+      ///
+      /// It returns a random integer uniformly from the whole range of
+      /// the current \c Number type. The default result type of this
+      /// function is \c int.
+      template <typename Number>
+      Number integer() {
+        static const int nb = std::numeric_limits<Number>::digits +
+          (std::numeric_limits<Number>::is_signed ? 1 : 0);


More information about the Lemon-commits mailing list