Split random number functions from misc.cpp to dedicated file
[lsnes.git] / src / lua / random.cpp
blob4fde313461dd1b6a58e768127c1b223132ae1100
1 #include "lua/internal.hpp"
2 #include "lua/unsaferewind.hpp"
3 #include "core/random.hpp"
4 #include "library/string.hpp"
5 #include "library/hex.hpp"
7 namespace
9 uint64_t randnum()
11 return hex::from<uint64_t>(get_random_hexstring(16));
14 uint64_t randnum_mod(uint64_t y)
16 uint64_t rmultA = std::numeric_limits<uint64_t>::max() % y;
17 uint64_t rmultB = std::numeric_limits<uint64_t>::max() / y;
18 if(rmultA == y - 1) {
19 //Exact div.
20 return randnum() % y;
21 } else {
22 //Not exact.
23 uint64_t bound = y * rmultB;
24 uint64_t x = bound;
25 while(x >= bound)
26 x = randnum();
27 return x % y;
31 int rand_boolean(lua::state& L, lua::parameters& P)
33 L.pushboolean(randnum() % 2);
34 return 1;
37 int rand_integer(lua::state& L, lua::parameters& P)
39 uint64_t low = 0, high = 0;
41 P(low);
43 if(P.is_number()) {
44 P(high);
45 if(low > high)
46 throw std::runtime_error("random.integer: high > low");
47 } else {
48 high = low - 1;
49 low = 0;
50 if(high < 0)
51 throw std::runtime_error("random.integer: high > low");
53 uint64_t rsize = high - low + 1;
54 L.pushnumber(low + randnum_mod(rsize));
55 return 1;
58 int rand_float(lua::state& L, lua::parameters& P)
60 double _bits = 0;
61 uint64_t* bits = (uint64_t*)&_bits;
62 *bits = randnum() & 0xFFFFFFFFFFFFFULL;
63 *bits |= 0x3FF0000000000000ULL;
64 L.pushnumber(_bits - 1);
65 return 1;
68 int rand_among(lua::state& L, lua::parameters& P)
70 unsigned args = 1;
71 while(P.more()) {
72 P.skip();
73 args++;
75 args--;
76 if(!args) {
77 L.pushnil();
78 return 1;
80 uint64_t n = randnum_mod(args);
81 L.pushvalue(n + 1);
82 return 1;
85 int rand_amongtable(lua::state& L, lua::parameters& P)
87 int ltbl;
88 P(P.table(ltbl));
90 uint64_t size = 0;
91 L.pushnil();
92 while(L.next(ltbl)) {
93 size++;
94 L.pop(1);
96 if(!size) {
97 L.pushnil();
98 return 1;
100 uint64_t n = randnum_mod(size);
101 L.pushnil();
102 for(uint64_t i = 0; i < n; i++) {
103 if(!L.next(ltbl))
104 throw std::runtime_error("random.amongtable: Inconsistent table size");
105 L.pop(1);
107 if(!L.next(ltbl))
108 throw std::runtime_error("random.amongtable: Inconsistent table size");
109 return 1;
112 lua::functions lua_random(lua_func_bit, "random", {
113 {"boolean", rand_boolean},
114 {"integer", rand_integer},
115 {"float", rand_float},
116 {"among", rand_among},
117 {"amongtable", rand_amongtable},