pure-cpp 1.0.0
A C++ physics simulation benchmark comparing performance with Python implementations
pcg_random.hpp
Go to the documentation of this file.
1#ifndef PCG_RANDOM_HPP
2#define PCG_RANDOM_HPP
3
4/**
5 * \file pcg_random.hpp
6 * \brief A minimal C++ implementation of the PCG32 random number generator.
7 * \author M.E. O'Neill (original implementation)
8 * \ingroup UtilsRandom
9 *
10 * This file provides a standalone implementation of pcg32, a 32-bit output
11 * random number generator from the PCG family. It is designed to be a drop-in
12 * replacement for standard C++ random number engines like std::mt19937.
13 *
14 * The PCG family of generators is known for its excellent statistical
15 * properties, small code size, and high performance.
16 *
17 * This implementation is based on the C++ code provided on the official PCG
18 * website: http://www.pcg-random.org/
19 *
20 * The original PCG library is distributed under the MIT or Apache 2.0
21 * licenses. This minimal version is provided for convenience.
22 */
23
24#include <cstdint>
25#include <limits>
26
27namespace Rng {
28
29 /**
30 * \brief A 32-bit Permuted Congruential Generator (pcg32).
31 * \ingroup UtilsRandom
32 *
33 * This class implements the `UniformRandomBitGenerator` concept from the
34 * C++ standard library, making it compatible with distribution classes like
35 * `std::uniform_int_distribution` and `std::uniform_real_distribution`.
36 */
37 class Pcg32 {
38 public:
39 /// \brief The result type of the generator, required by the
40 /// UniformRandomBitGenerator concept.
41 using result_type = uint32_t;
42
43 /**
44 * \brief Returns the minimum value the generator can produce.
45 * \return The minimum value (0).
46 */
47 static constexpr result_type min() {
48 return std::numeric_limits<result_type>::min();
49 }
50
51 /**
52 * \brief Returns the maximum value the generator can produce.
53 * \return The maximum value.
54 */
55 static constexpr result_type max() {
56 return std::numeric_limits<result_type>::max();
57 }
58
59 /**
60 * \brief Default constructor. Initializes the generator with a default
61 * seed.
62 */
63 Pcg32() : state_(0x853c49e6748fea9bULL), inc_(0xda3e39cb94b95bdbULL) {}
64
65 /**
66 * \brief Constructs the generator with a specific seed.
67 * \param seed The initial seed value for the generator's state.
68 */
69 explicit Pcg32(uint64_t seed) { this->seed(seed); }
70
71 /**
72 * \brief Seeds the random number generator.
73 *
74 * \param init_seed The seed value. The stream is also initialised
75 * based on this seed.
76 */
77 void seed(uint64_t init_seed) {
78 state_ = 0;
79 inc_ = (init_seed << 1) | 1;
80 (*this)(); // Advance the generator once
81 state_ += 0x853c49e6748fea9bULL;
82 (*this)(); // Advance again
83 }
84
85 /**
86 * \brief Generates the next random number in the sequence.
87 * \return A 32-bit unsigned random integer.
88 */
90 const uint64_t old_state = state_;
91 // Advance internal state
92 state_ = old_state * 6364136223846793005ULL + (inc_ | 1);
93 // Calculate output function (XSH-RR)
94 const uint32_t xorshifted =
95 static_cast<uint32_t>(((old_state >> 18u) ^ old_state) >> 27u);
96 const uint32_t rot = static_cast<uint32_t>(old_state >> 59u);
97 return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
98 }
99
100 /**
101 * \brief Discards a specified number of values from the sequence.
102 * \param z The number of values to discard.
103 */
104 void discard(unsigned long long z) {
105 for (unsigned long long i = 0; i < z; ++i) {
106 (*this)();
107 }
108 }
109
110 // Equality and inequality operators
111 /**
112 * \brief Checks if two generators have the same internal state.
113 * \return True if the state and stream are identical.
114 */
115 friend bool operator==(const Pcg32& lhs, const Pcg32& rhs) {
116 return lhs.state_ == rhs.state_ && lhs.inc_ == rhs.inc_;
117 }
118 /**
119 * \brief Checks if two generators have different internal states.
120 * \return True if the state or stream are different.
121 */
122 friend bool operator!=(const Pcg32& lhs, const Pcg32& rhs) {
123 return !(lhs == rhs);
124 }
125
126 private:
127 /// \brief The internal state of the generator.
128 uint64_t state_;
129 /**
130 * \brief The stream selector, which determines the sequence. Must be
131 * odd.
132 */
133 uint64_t inc_;
134 };
135
136} // namespace Rng
137
138#endif // PCG_RANDOM_HPP
A 32-bit Permuted Congruential Generator (pcg32).
Definition: pcg_random.hpp:37
uint64_t state_
The internal state of the generator.
Definition: pcg_random.hpp:128
uint32_t result_type
The result type of the generator, required by the UniformRandomBitGenerator concept.
Definition: pcg_random.hpp:41
void seed(uint64_t init_seed)
Seeds the random number generator.
Definition: pcg_random.hpp:77
static constexpr result_type min()
Returns the minimum value the generator can produce.
Definition: pcg_random.hpp:47
friend bool operator==(const Pcg32 &lhs, const Pcg32 &rhs)
Checks if two generators have the same internal state.
Definition: pcg_random.hpp:115
void discard(unsigned long long z)
Discards a specified number of values from the sequence.
Definition: pcg_random.hpp:104
result_type operator()()
Generates the next random number in the sequence.
Definition: pcg_random.hpp:89
Pcg32()
Default constructor. Initializes the generator with a default seed.
Definition: pcg_random.hpp:63
friend bool operator!=(const Pcg32 &lhs, const Pcg32 &rhs)
Checks if two generators have different internal states.
Definition: pcg_random.hpp:122
static constexpr result_type max()
Returns the maximum value the generator can produce.
Definition: pcg_random.hpp:55
Pcg32(uint64_t seed)
Constructs the generator with a specific seed.
Definition: pcg_random.hpp:69
uint64_t inc_
The stream selector, which determines the sequence. Must be odd.
Definition: pcg_random.hpp:133