The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
random.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2014 - 2025
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
25static 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
31static_assert(std::numeric_limits<double>::is_iec559, "Floating point representation is not IEEE 754-compliant");
32
33namespace {
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
57namespace 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
85 {
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")