1#include "prng.h"
2
3#include <base/dbg.h>
4#include <base/str.h>
5
6// From https://en.wikipedia.org/w/index.php?title=Permuted_congruential_generator&oldid=901497400#Example_code.
7//
8// > The generator recommended for most users is PCG-XSH-RR with 64-bit state
9// > and 32-bit output.
10
11#define NAME "pcg-xsh-rr"
12
13CPrng::CPrng() :
14 m_Seeded(false)
15{
16}
17
18const char *CPrng::Description() const
19{
20 if(!m_Seeded)
21 {
22 return NAME ":unseeded";
23 }
24 return m_aDescription;
25}
26
27static unsigned int RotateRight32(unsigned int x, int Shift)
28{
29 return (x >> Shift) | (x << (-Shift & 31));
30}
31
32void CPrng::Seed(uint64_t aSeed[2])
33{
34 m_Seeded = true;
35 str_format(buffer: m_aDescription, buffer_size: sizeof(m_aDescription), format: "%s:%08x%08x:%08x%08x", NAME,
36 (unsigned)(aSeed[0] >> 32), (unsigned)aSeed[0],
37 (unsigned)(aSeed[1] >> 32), (unsigned)aSeed[1]);
38
39 m_Increment = (aSeed[1] << 1) | 1;
40 m_State = aSeed[0] + m_Increment;
41 RandomBits();
42}
43
44unsigned int CPrng::RandomBits()
45{
46 dbg_assert(m_Seeded, "prng needs to be seeded before it can generate random numbers");
47
48 uint64_t x = m_State;
49 unsigned int Count = x >> 59;
50
51 static const uint64_t s_Multiplier = 6364136223846793005u;
52 m_State = x * s_Multiplier + m_Increment;
53 x ^= x >> 18;
54 return RotateRight32(x: x >> 27, Shift: Count);
55}
56