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