The Battle for Wesnoth  1.17.0-dev
random.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2021
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "random.hpp"
17 #include "log.hpp"
18 
19 #include <boost/random/random_device.hpp>
20 
21 #include <cassert>
22 #include <cstdlib>
23 #include <limits>
24 #include <random>
25 
26 static lg::log_domain log_random("random");
27 #define DBG_RND LOG_STREAM(debug, log_random)
28 #define LOG_RND LOG_STREAM(info, log_random)
29 #define WRN_RND LOG_STREAM(warn, log_random)
30 #define ERR_RND LOG_STREAM(err, log_random)
31 
32 static_assert(std::numeric_limits<double>::is_iec559, "Floating point representation is not IEEE 754-compliant");
33 
34 namespace {
35 
36  class rng_default : public randomness::rng
37  {
38  public:
39  rng_default()
40  : gen_()
41  {
42  /* Note: do not replace this with std::random_device.
43  * @cbeck88 told in IRC (2016-10-16) that std::random_device
44  * is very poorly implemented in MinGW. */
45  boost::random_device entropy_source;
46  gen_.seed(entropy_source());
47  }
48  protected:
49  virtual uint32_t next_random_impl()
50  {
51  return gen_();
52  }
53  private:
54  std::mt19937 gen_;
55  };
56 }
57 
58 namespace randomness
59 {
60 
61  rng* generator = &rng::default_instance();
62 
63  rng::rng()
64  : random_calls_(0)
65  {
66 
67  }
68 
70  {
71 
72  }
73 
75  {
76  static rng* def = new rng_default();
77  return *def;
78  }
79 
80  unsigned int rng::get_random_calls() const
81  {
82  return random_calls_;
83  }
84 
85  uint32_t rng::next_random()
86  {
87  random_calls_++;
88  return next_random_impl();
89  }
90 
91  /**
92  * This code is based on the boost implementation of uniform_smallint.
93  * http://www.boost.org/doc/libs/1_55_0/boost/random/uniform_smallint.hpp
94  * Using that code would be ideal, except that boost, and C++11, do not
95  * guarantee that it will work the same way on all platforms, or that the
96  * results may not be different in future versions of the library.
97  * The simplified version I have written should work the same on all
98  * platforms, which is the most important thing for us.
99  * The existence of "modulo bias" seems less important when we have moved
100  * to std::mt19937, since it guarantees that there are no "bad bits"
101  * and has a very large range.
102  *
103  * If a standard cross platform version becomes available then this should
104  * be replaced.
105  */
107  {
108  assert(max >= 0);
109  return static_cast<int> (next_random() % (static_cast<uint32_t>(max)+1));
110  }
111 
113  {
114  union
115  {
116  double floating_point_number;
117  uint64_t integer;
118  } number;
119 
120  number.integer = 0u;
121  /* Exponent. It's set to zero.
122  Exponent bias is 1023 in double precision, and therefore the value 1023
123  needs to be encoded. */
124  number.integer |= static_cast<uint64_t>(1023) << 52;
125  /* Significand. A double-precision floating point number stores 52 significand bits.
126  The underlying RNG only gives us 32 bits, so we need to shift the bits 20 positions
127  to the left. The last 20 significand bits we can leave at zero, we don't need
128  the full 52 bits of randomness allowed by the double-precision format. */
129  number.integer |= static_cast<uint64_t>(next_random()) << (52 - 32);
130  /* At this point, the exponent is zero. The significand, taking into account the
131  implicit leading one bit, is at least exactly one and at most almost two.
132  In other words, interpreting the value as a double gives us a number in the range
133  [1, 2[. Simply subtract one from that value and return it. */
134  return number.floating_point_number - 1.0;
135  }
136 
137  bool rng::get_random_bool(double probability)
138  {
139  assert(probability >= 0.0 && probability <= 1.0);
140  return get_random_double() < probability;
141  }
142 }
int get_random_int_in_range_zero_to(int max)
Does the hard work of get_random_int.
Definition: random.cpp:106
virtual ~rng()
Definition: random.cpp:69
double get_random_double()
This helper method returns a floating-point number in the range [0,1[.
Definition: random.cpp:112
unsigned int get_random_calls() const
Provides the number of random calls to the rng in this context.
Definition: random.cpp:80
virtual uint32_t next_random_impl()=0
bool get_random_bool(double probability)
This helper method returns true with the probability supplied as a parameter.
Definition: random.cpp:137
static lg::log_domain log_random("random")
rng * generator
This generator is automatically synced during synced context.
Definition: random.cpp:61
Standard logging facilities (interface).
unsigned int random_calls_
Definition: random.hpp:94
uint32_t next_random()
Provides the next random draw.
Definition: random.cpp:85
static rng & default_instance()
Definition: random.cpp:74
this class does not give synced random results derived classes might do.
Definition: random.hpp:28