A small tweak to lua random

This commit is contained in:
2022-04-06 15:09:28 -04:00
parent 89365ea9ba
commit 453809b65c
3 changed files with 18 additions and 4 deletions

View File

@@ -157,6 +157,10 @@ uint64_t hash_ints(uint64_t a, uint64_t b, uint64_t c, uint64_t d) {
return h1; return h1;
} }
double hash_to_double(uint64_t hash) {
return (hash >> (64-53)) * 0x1p-53;
}
StringVec split(const eng::string &s, char sep) { StringVec split(const eng::string &s, char sep) {
StringVec result; StringVec result;
int start = 0; int start = 0;
@@ -498,6 +502,10 @@ LuaDefine(unittests_util, "", "some unit tests") {
LuaAssertStrEq(L, util::hash_to_hex(util::HashValue(0x1234,0x789a)), LuaAssertStrEq(L, util::hash_to_hex(util::HashValue(0x1234,0x789a)),
"0000000000001234000000000000789a"); "0000000000001234000000000000789a");
// Test hash_to_double
LuaAssert(L, util::hash_to_double(0x1000000000000000) == 1.0/16.0);
LuaAssert(L, util::hash_to_double(0x7000000000000000) == 7.0/16.0);
LuaAssert(L, util::hash_to_double(0xF000000000000000) == 15.0/16.0);
return 0; return 0;
} }

View File

@@ -70,6 +70,9 @@ eng::string hash_to_hex(const HashValue &hash);
// This is a good hash, but not cryptographically good. // This is a good hash, but not cryptographically good.
uint64_t hash_ints(uint64_t n1, uint64_t n2, uint64_t n3, uint64_t n4); uint64_t hash_ints(uint64_t n1, uint64_t n2, uint64_t n3, uint64_t n4);
// Convert a 64-bit hash value into a floating point number between 0 and 1.
double hash_to_double(uint64_t hash);
// Split a string into multiple strings // Split a string into multiple strings
StringVec split(const eng::string &s, char sep); StringVec split(const eng::string &s, char sep);

View File

@@ -412,12 +412,15 @@ LuaDefine(math_random, "(args...)",
} }
} }
// Generate the hash and convert to a lua_Number.
uint64_t hash = util::hash_ints(seed, count, salt, 456);
if (!have_range) { if (!have_range) {
double result = (hash & LuaStack::MAXINT) * 0x1p-53; // Generate the hash and convert to a double.
lua_pushnumber(L, result); uint64_t hash = util::hash_ints(seed, count, salt, 456);
lua_pushnumber(L, util::hash_to_double(hash));
} else { } else {
// Generate the hash and scale it into the desired range.
// This code is not quite right: the results are not quite
// uniform, this is especially true for very long ranges.
uint64_t hash = util::hash_ints(seed, count, salt, 456);
uint64_t range = (high - low) + 1; uint64_t range = (high - low) + 1;
uint64_t offset = (hash & 0x7FFFFFFFFFFFFFFF) % range; uint64_t offset = (hash & 0x7FFFFFFFFFFFFFFF) % range;
int64_t result = low + int64_t(offset); int64_t result = low + int64_t(offset);