Euphoria
random.cc
Go to the documentation of this file.
1 #include "base/random.h"
2 
3 #include "base/numeric.h"
4 #include "base/range.h"
5 
6 #include <limits>
7 #include <ctime>
8 
9 namespace eu
10 {
11  /*
12 There are much better choices than Mersenne Twister nowadays. Here is a RNG
13 called WELL512, designed by the designers of Mersenne, developed 10 years later,
14 and an all around better choice for games. The code is put in the public domain
15 by Dr. Chris Lomont. He claims this implementation is 40% faster than Mersenne,
16 does not suffer from poor diffusion and trapping when the state contains many 0
17 bits, and is clearly a lot simpler code. It has a period of 2^512; a PC takes
18 over 10^100 years to cycle through the states, so it is large enough.
19 Here is a paper overviewing PRNGs where I found the WELL512 implementation.
20 http://www.lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf
21 So - faster, simpler, created by the same designers 10 years later, and produces
22 better numbers than Mersenne. How can you go wrong? :)
23 */
24  // http://stackoverflow.com/questions/1046714/what-is-a-good-random-number-generator-for-a-game
25  // http://stackoverflow.com/a/1227137
26 
27  U32
29  {
30  // idea from http://www.eternallyconfuzzled.com/arts/jsw_art_rand.aspx
31  time_t now = time(nullptr);
32 
33  auto* bytes = reinterpret_cast<unsigned char*>(&now);
34  U32 seed = 0;
35 
36  for(size_t byte_index = 0; byte_index < sizeof(time_t); byte_index++)
37  {
38  seed = seed * (std::numeric_limits<unsigned char>::max() + 2U) + bytes[byte_index];
39  }
40 
41  return seed;
42  }
43 
45  : index(0), state {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
46  {
47  for(U32 state_index = 0; state_index < 16; ++state_index)
48  {
49  state[state_index] = seed * state_index;
50  }
51  }
52 
53  U32
55  {
56  U32 a = state[index];
57  U32 c = state[(index + 13) & 15];
58  U32 b = a ^ c ^ (a << 16) ^ (c << 15);
59  c = state[(index + 9) & 15];
60  c ^= (c >> 11);
61  a = state[index] = b ^ c;
62  U32 d = a ^ ((a << 5) & 0xDA442D24UL);
63  index = (index + 15) & 15;
64  a = state[index];
65  state[index] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28);
66  return state[index];
67  }
68 
69  U64
71  {
72  const U64 a = get_next_u32();
73  const U64 b = get_next_u32();
74  return (a << 32) | b;
75  }
76 
77  float
79  {
80  return static_cast<float>(get_next_u32()) / static_cast<float>(std::numeric_limits<U32>::max());
81  }
82 
83  float
85  {
86  // gaussian source:
87  // https://www.alanzucconi.com/2015/09/16/how-to-sample-from-a-gaussian-distribution/
88  float v1 = 0;
89  float v2 = 0;
90  float s = 0;
91  do
92  {
93  v1 = get_random_in_range(rand, r11);
94  v2 = get_random_in_range(rand, r11);
95  s = v1 * v1 + v2 * v2;
96  } while(s >= 1.0f || is_zero(s));
97 
98  s = sqrt((-2.0f * std::log(s)) / s);
99 
100  return v1 * s;
101  }
102 
103  float
104  get_random_gaussian(Random* rand, float mean, float std_dev)
105  {
106  return mean + get_random_gaussian_float01(rand) * std_dev;
107  }
108 
109  float
110  get_random_gaussian(Random* rand, float mean, float std_dev, const Range<float>& r)
111  {
112  float x = 0;
113  do
114  {
115  x = get_random_gaussian(rand, mean, std_dev);
116  } while(!is_within(r, x));
117  return x;
118  }
119 
120  bool
122  {
123  return get_next_float01() > 0.5f;
124  }
125 
126  int
128  {
129  return get_next_bool() ? 1 : -1;
130  }
131 
132  vec2f
134  {
135  const auto angle = Angle::from_percent_of_360(r->get_next_float01());
136  const auto dist = r->get_next_float01() * 0.5f;
137 
138  return vec2f {dist * cos(angle) + 0.5f, dist * sin(angle) + 0.5f};
139  }
140 
141  vec2f
143  {
144  // http://xdpixel.com/random-points-in-a-circle/
145  const auto angle = Angle::from_percent_of_360(r->get_next_float01());
146  const auto dist = sqrt(r->get_next_float01()) * 0.5f;
147 
148  return vec2f {dist * cos(angle) + 0.5f, dist * sin(angle) + 0.5f};
149  }
150 }
Definition: assert.h:90
float sqrt(float r)
Definition: numeric.cc:101
float get_random_gaussian_float01(Random *rand)
Definition: random.cc:84
std::uint32_t U32
Definition: ints.h:13
bool is_zero(int r)
Definition: numeric.cc:20
T get_random_in_range(Random *rand, const Range< T > &range)
Definition: random.h:50
vec2f get_random_point_on_unit_circle_center_focused(Random *r)
Definition: random.cc:133
float cos(const Angle &ang)
Definition: angle.cc:68
std::uint64_t U64
Definition: ints.h:12
float sin(const Angle &ang)
Definition: angle.cc:61
bool is_within(const Range< T > &range, T value)
Definition: range.h:108
size2f max(const size2f lhs, const size2f rhs)
Definition: size2.cc:149
constexpr Range< float > r11
Definition: range.h:58
float get_random_gaussian(Random *rand, float mean, float std_dev)
Definition: random.cc:104
vec2f get_random_point_on_unit_circle_uniform(Random *r)
Definition: random.cc:142
constexpr float from_percent_of_360() const
Definition: angle.h:56
WEL512 Random Number Generator.
Definition: random.h:21
U32 index
Definition: random.h:22
float get_next_float01()
Definition: random.cc:78
bool get_next_bool()
Definition: random.cc:121
U32 get_next_u32()
Definition: random.cc:54
U64 get_next_u64()
Definition: random.cc:70
int get_next_sign()
Definition: random.cc:127
Random(U32 seed=generate_time_seed())
Definition: random.cc:44
static U32 generate_time_seed()
Definition: random.cc:28
U32 state[16]
Definition: random.h:23
Definition: vec2.h:33
ParserState state
Definition: ui_text.cc:134