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