1+ #include " components/rng/PCG.h"
2+
3+ Pinetime::Controllers::RNG::State Pinetime::Controllers::RNG::Seed (Pinetime::Controllers::RNG::rng_uint s, Pinetime::Controllers::RNG::rng_uint i) {
4+ rng.state = 0u ;
5+ rng.inc = i | 1u ;
6+ Generate ();
7+ rng.state += s;
8+ Generate ();
9+ return rng;
10+ }
11+
12+ Pinetime::Controllers::RNG::State Pinetime::Controllers::RNG::Seed () {
13+ using namespace Pinetime ::Controllers;
14+ Pinetime::Controllers::RNG::State new_rng;
15+ new_rng.state = (RNG::rng_uint) Generate () << (sizeof (new_rng.state ) * 4 ) ^ (RNG::rng_uint) Generate ();
16+ new_rng.inc = (RNG::rng_uint) Generate () << (sizeof (new_rng.inc ) * 4 ) ^ (RNG::rng_uint) Generate ();
17+ return new_rng;
18+ }
19+
20+ // *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
21+ // Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
22+ // Website: https://www.pcg-random.org/download.html
23+ // See: https://www.apache.org/licenses/GPL-compatibility.html
24+ /*
25+ uint64_t oldstate = rng.state;
26+ // Advance internal state
27+ rng.state = oldstate * 6364136223846793005ULL + (rng.inc | 1);
28+ // Calculate output function (XSH RR), uses old state for max ILP
29+ uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
30+ uint32_t rot = oldstate >> 59u;
31+ return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
32+ */
33+ Pinetime::Controllers::RNG::rng_out Pinetime::Controllers::RNG::Generate () {
34+ using namespace Pinetime ::Controllers;
35+ // See magic numbers in https://github.com/imneme/pcg-cpp/blob/master/include/pcg_random.hpp
36+ constexpr uint32_t tbits = sizeof (rng.state ) * 8 ;
37+ constexpr uint32_t ibits = sizeof (rng.inc ) * 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 = sizeof (RNG::rng_out) * 8 - opbits;
63+ constexpr uint32_t s1 = (sizeof (RNG::rng_out) * 8 + 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