1+ #include " components/rng/PCG.h"
2+
3+ Pinetime::Controllers::RNG::State Pinetime::Controllers::RNG::Seed (Pinetime::Controllers::RNG::rng_uint s,
4+ Pinetime::Controllers::RNG::rng_uint i) {
5+ rng.state = 0u ;
6+ rng.inc = i | 1u ;
7+ Generate ();
8+ rng.state += s;
9+ Generate ();
10+ return rng;
11+ }
12+
13+ Pinetime::Controllers::RNG::State Pinetime::Controllers::RNG::Seed () {
14+ using namespace Pinetime ::Controllers;
15+ Pinetime::Controllers::RNG::State new_rng;
16+ new_rng.state = (RNG::rng_uint) Generate () << (sizeof (new_rng.state ) * 4 ) ^ (RNG::rng_uint) Generate ();
17+ new_rng.inc = (RNG::rng_uint) Generate () << (sizeof (new_rng.inc ) * 4 ) ^ (RNG::rng_uint) Generate ();
18+ return new_rng;
19+ }
20+
21+ // *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
22+ // Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
23+ // Website: https://www.pcg-random.org/download.html
24+ // See: https://www.apache.org/licenses/GPL-compatibility.html
25+ /*
26+ uint64_t oldstate = rng.state;
27+ // Advance internal state
28+ rng.state = oldstate * 6364136223846793005ULL + (rng.inc | 1);
29+ // Calculate output function (XSH RR), uses old state for max ILP
30+ uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
31+ uint32_t rot = oldstate >> 59u;
32+ return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
33+ */
34+ Pinetime::Controllers::RNG::rng_out Pinetime::Controllers::RNG::Generate () {
35+ using namespace Pinetime ::Controllers;
36+ // See magic numbers in https://github.com/imneme/pcg-cpp/blob/master/include/pcg_random.hpp
37+ constexpr uint32_t tbits = sizeof (rng.state ) * 8 ;
38+ constexpr uint32_t sbits = sizeof (rng) * 8 ;
39+ constexpr uint32_t obits = sizeof (RNG::rng_out) * 8 ;
40+
41+ constexpr rng_uint multiplier = tbits >= 64 ? 1442695040888963407ULL : tbits >= 32 ? 747796405U : tbits >= 16 ? 12829U : 141u ;
42+
43+ constexpr uint32_t opbits = sbits - 5 >= 64 ? 5u : // 128 bits -> 5
44+ sbits - 4 >= 32 ? 4u
45+ : // 64 bits -> 4
46+ sbits - 3 >= 16 ? 3u
47+ : // 32 bits -> 3
48+ sbits - 2 >= 8 ? 2u
49+ : // 16 bits -> 2
50+ sbits - 1 >= 1 ? 1u
51+ : // 8 bits -> 1
52+ 0u ;
53+
54+ auto oldstate = rng.state ;
55+ rng.state = oldstate * multiplier + (rng.inc | 1 );
56+ // 64 bits of state, 32 output (64 - 5 = 59, 32 - 5 = 27 and floor((5+32)/2) = 18)
57+ // 2^5 = 32*
58+ // output = rotate<s3,s2,s1>(state ^ (state >> s1)) >> s2, state >> s3)
59+ // 32 bits of state, 16 output (32 - 4 = 28, 16 - 4 = 12, and floor((4 + 16)/2) = 10)
60+ // 2^4 = 16*
61+ constexpr uint32_t s3 = tbits - opbits;
62+ constexpr uint32_t s2 = obits - opbits;
63+ constexpr uint32_t s1 = (obits + 5 ) / 2 ;
64+
65+ constexpr RNG::rng_out mask = (1 << opbits) - 1 ;
66+ RNG::rng_out xorshifted = ((oldstate >> s1) ^ oldstate) >> s2;
67+ rng_out rot = oldstate >> s3;
68+ // rotate
69+ return (xorshifted >> rot) | (xorshifted << ((-rot) & mask));
70+ };
71+
72+ // Lemire's Method (slight rewrite) [0, range)
73+ Pinetime::Controllers::RNG::rng_out Pinetime::Controllers::RNG::GenerateBounded (Pinetime::Controllers::RNG::rng_out range) {
74+ using namespace Pinetime ::Controllers;
75+ rng_uint m;
76+ RNG::rng_out t = (-range) % range;
77+ RNG::rng_out l;
78+
79+ do {
80+ RNG::rng_out x = Generate ();
81+ m = RNG::rng_uint (x) * RNG::rng_uint (range);
82+ l = RNG::rng_out (m);
83+ } while (l < t);
84+
85+ return m >> (sizeof (RNG::rng_out) * 8 );
86+ };
0 commit comments