11#include " components/rng/PCG.h"
22
3- Pinetime::Controllers::RNG::State Pinetime::Controllers::RNG::Seed (Pinetime::Controllers::RNG::rng_uint s,
4- Pinetime::Controllers::RNG::rng_uint i) {
5- return rng = State (s, i);
6- }
3+ using namespace Pinetime ::Controllers;
74
8- Pinetime::Controllers::RNG::State Pinetime::Controllers::RNG::Seed () {
9- using namespace Pinetime ::Controllers;
10- Pinetime::Controllers::RNG::State new_rng ((uint64_t ) Generate () << 32 ^ (uint64_t ) Generate (),
11- (uint64_t ) Generate () << 32 ^ (uint64_t ) Generate ());
12- return new_rng;
13- }
5+ // pcg_state_setseq_64::pcg_state_setseq_64(uint64_t s, uint64_t i) : state(s), inc(i) {};
6+ // RNG::RNG() : rng {0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL} {};
147
15- Pinetime::Controllers::RNG::rng_out Pinetime::Controllers::RNG::Generate () {
16- return rng ();
8+ RNG::RNG (result_type value) {
9+ // pcg32_srandom_r(&rng, 0x853c49e6748fea9bULL, value);
10+ rng.state = 0U ;
11+ rng.inc = (value << 1u ) | 1u ;
12+ (*this )(); // pcg32_random_r(rng);
13+ rng.state += 0x853c49e6748fea9bULL ;
14+ (*this )(); // pcg32_random_r(rng);
1715};
1816
19- // See pcg-cpp/sample/codebook.cpp
20- Pinetime::Controllers::RNG::rng_out Pinetime::Controllers::RNG::GenerateBounded (Pinetime::Controllers::RNG::rng_out range) {
21- return rng (range);
17+ RNG& RNG::operator =(const pcg32_random_t & other) {
18+ rng.state = other.state ;
19+ rng.inc = other.inc | 1 ;
20+ return *this ;
21+ };
22+
23+ template <class SeedSeq >
24+ RNG::RNG (SeedSeq& seq) {
25+ seed (seq);
26+ };
27+ /*
28+ RNG::RNG(const RNG& other) {
29+ RNG tmp = other;
30+ RNG::result_type* ptr = (RNG::result_type*) this;
31+ tmp.generate(ptr, ptr + (sizeof(RNG) / sizeof(RNG::result_type)));
32+ };
33+ */
34+ template <typename SeedSeq>
35+ void RNG::seed (SeedSeq& seq) {
36+ RNG::result_type* ptr = (RNG::result_type*) this ;
37+ seq.generate (ptr, ptr + (sizeof (RNG) / sizeof (RNG::result_type)));
38+ rng.inc |= 1 ;
39+ };
40+
41+ void RNG::seed (RNG& other) {
42+ RNG::result_type* ptr = (RNG::result_type*) this ;
43+ other.generate (ptr, ptr + (sizeof (RNG) / sizeof (RNG::result_type)));
44+ rng.inc |= 1 ;
45+ };
46+
47+ RNG::result_type RNG::operator ()() {
48+ // return pcg32_random_r(&rng);
49+ uint64_t oldstate = rng.state ;
50+ rng.state = oldstate * 6364136223846793005ULL + rng.inc ;
51+ uint32_t xorshifted = ((oldstate >> 18u ) ^ oldstate) >> 27u ;
52+ uint32_t rot = oldstate >> 59u ;
53+ return (xorshifted >> rot) | (xorshifted << ((-rot) & 31 ));
54+ };
55+
56+ RNG::result_type RNG::operator ()(RNG::result_type bound) {
57+ // return pcg32_boundedrand_r(&rng, bounds);
58+ // To avoid bias, we need to make the range of the RNG a multiple of
59+ // bound, which we do by dropping output less than a threshold.
60+ // A naive scheme to calculate the threshold would be to do
61+ //
62+ // uint32_t threshold = 0x100000000ull % bound;
63+ //
64+ // but 64-bit div/mod is slower than 32-bit div/mod (especially on
65+ // 32-bit platforms). In essence, we do
66+ //
67+ // uint32_t threshold = (0x100000000ull-bound) % bound;
68+ //
69+ // because this version will calculate the same modulus, but the LHS
70+ // value is less than 2^32.
71+
72+ uint32_t threshold = -bound % bound;
73+
74+ // Uniformity guarantees that this loop will terminate. In practice, it
75+ // should usually terminate quickly; on average (assuming all bounds are
76+ // equally likely), 82.25% of the time, we can expect it to require just
77+ // one iteration. In the worst case, someone passes a bound of 2^31 + 1
78+ // (i.e., 2147483649), which invalidates almost 50% of the range. In
79+ // practice, bounds are typically small and only a tiny amount of the range
80+ // is eliminated.
81+ for (;;) {
82+ uint32_t r = (*this )(); // pcg32_random_r(rng);
83+ if (r >= threshold)
84+ return r % bound;
85+ }
86+ };
87+
88+ // std::seed_seq interface
89+ template <typename It>
90+ void RNG::generate (It start, It end) {
91+ for (; start != end; ++start)
92+ *start = (*this )();
93+ };
94+
95+ std::size_t RNG::size () const noexcept {
96+ return sizeof (rng) / sizeof (RNG::result_type);
97+ };
98+
99+ template <class OutputIt >
100+ void RNG::param (OutputIt dest) const {
101+ std::size_t i = 0 ;
102+ const std::size_t n = size ();
103+ RNG::result_type* ptr = (RNG::result_type*) this ;
104+ for (; i < n; ++i, ++dest, ++ptr) {
105+ *dest = ptr;
106+ }
22107};
0 commit comments