Simplify LuaPseudoRandom::l_next and fix docs

Also extends the allowed range on the C++ side. This has no side-effects.
This commit is contained in:
sfan5 2024-01-10 20:08:00 +01:00
parent d20f1182f2
commit e824e9023f
5 changed files with 22 additions and 20 deletions

View File

@ -8061,7 +8061,9 @@ A 32-bit pseudorandom number generator.
Uses PCG32, an algorithm of the permuted congruential generator family, Uses PCG32, an algorithm of the permuted congruential generator family,
offering very strong randomness. offering very strong randomness.
It can be created via `PcgRandom(seed)` or `PcgRandom(seed, sequence)`. * constructor `PcgRandom(seed, [seq])`
* `seed`: 64-bit unsigned seed
* `seq`: 64-bit unsigned sequence, optional
### Methods ### Methods
@ -8156,14 +8158,15 @@ Can be obtained using `player:get_meta()`.
A 16-bit pseudorandom number generator. A 16-bit pseudorandom number generator.
Uses a well-known LCG algorithm introduced by K&R. Uses a well-known LCG algorithm introduced by K&R.
It can be created via `PseudoRandom(seed)`. * constructor `PseudoRandom(seed)`
* `seed`: 32-bit signed number
### Methods ### Methods
* `next()`: return next integer random number [`0`...`32767`] * `next()`: return next integer random number [`0`...`32767`]
* `next(min, max)`: return next integer random number [`min`...`max`] * `next(min, max)`: return next integer random number [`min`...`max`]
* `((max - min) == 32767) or ((max-min) <= 6553))` must be true * Either `max - min == 32767` or `max - min <= 6553` must be true
due to the simple implementation making bad distribution otherwise. due to the simple implementation making a bad distribution otherwise.
`Raycast` `Raycast`
--------- ---------

View File

@ -6,6 +6,8 @@ local function test_random()
local pr2 = PseudoRandom(-101) local pr2 = PseudoRandom(-101)
assert(pr2:next(0, 100) == 35) assert(pr2:next(0, 100) == 35)
-- unusual case that is normally disallowed:
assert(pr2:next(10000, 42767) == 12485)
end end
unittests.register("test_random", test_random) unittests.register("test_random", test_random)

View File

@ -70,7 +70,7 @@ public:
PcgRandom, we cannot modify this RNG's range as it would change the PcgRandom, we cannot modify this RNG's range as it would change the
output of this RNG for reverse compatibility. output of this RNG for reverse compatibility.
*/ */
if ((u32)(max - min) > (RANDOM_RANGE + 1) / 10) if ((u32)(max - min) > (RANDOM_RANGE + 1) / 5)
throw PrngException("Range too large"); throw PrngException("Range too large");
return (next() % (max - min + 1)) + min; return (next() % (max - min + 1)) + min;

View File

@ -405,25 +405,22 @@ int LuaPseudoRandom::l_next(lua_State *L)
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
LuaPseudoRandom *o = checkObject<LuaPseudoRandom>(L, 1); LuaPseudoRandom *o = checkObject<LuaPseudoRandom>(L, 1);
int min = 0; int min = 0, max = PseudoRandom::RANDOM_RANGE;
int max = 32767;
lua_settop(L, 3);
if (lua_isnumber(L, 2)) if (lua_isnumber(L, 2))
min = luaL_checkinteger(L, 2); min = luaL_checkinteger(L, 2);
if (lua_isnumber(L, 3)) if (lua_isnumber(L, 3))
max = luaL_checkinteger(L, 3); max = luaL_checkinteger(L, 3);
if (max < min) {
errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl; int val;
throw LuaError("PseudoRandom.next(): max < min"); if (max - min == PseudoRandom::RANDOM_RANGE) {
val = o->m_pseudo.next() + min;
} else {
try {
val = o->m_pseudo.range(min, max);
} catch (PrngException &e) {
throw LuaError(e.what());
}
} }
if(max - min != 32767 && max - min > 32767/5)
throw LuaError("PseudoRandom.next() max-min is not 32767"
" and is > 32768/5. This is disallowed due to"
" the bad random distribution the"
" implementation would otherwise make.");
PseudoRandom &pseudo = o->m_pseudo;
int val = pseudo.next();
val = (val % (max-min+1)) + min;
lua_pushinteger(L, val); lua_pushinteger(L, val);
return 1; return 1;
} }

View File

@ -81,7 +81,7 @@ void TestRandom::testPseudoRandomRange()
{ {
PseudoRandom pr((int)time(NULL)); PseudoRandom pr((int)time(NULL));
EXCEPTION_CHECK(PrngException, pr.range(2000, 6000)); EXCEPTION_CHECK(PrngException, pr.range(2000, 8600));
EXCEPTION_CHECK(PrngException, pr.range(5, 1)); EXCEPTION_CHECK(PrngException, pr.range(5, 1));
for (u32 i = 0; i != 32768; i++) { for (u32 i = 0; i != 32768; i++) {