qoala / InvisibleInc-CommunityBugFixes

1 stars 0 forks source link

PRNG can repeat too quickly on certain inputs #71

Closed qoala closed 8 months ago

qoala commented 11 months ago

https://discord.com/channels/313015356052471828/313015598789427202/1138490245969625108

Cyberboy2000

Someone at Klei tried to take this c code https://web.archive.org/web/20050223151803/http://remus.rutgers.edu/~rhoads/Code/random.c and port it to lua. Problem is, almost all prng is built on integer arithmetic, but by default lua only uses floating point numbers. While it is true that a double-precision float can hold any 32-bit int, this is not the case for the product of two ints.

[...]

Inputting 2898587136 as the initial seed causes it to loop back on itself in only 5647 calls, rather than the ~2^32 it is supposed to take.

qoala commented 11 months ago

https://discord.com/channels/313015356052471828/313015598789427202/1159912000344825927

local function next( self )
    -- http://remus.rutgers.edu/~rhoads/Code/random.c
    -- LUA:
    -- Our assumption is that double-precision is encoded with 64 bits (according to IEEE 754)
    -- We have enough precision to handle all 32 bit unsigned integer representations, and calculate
    -- modulo 2^32 to generate single-point precision random values.

    local a, m, q, r1, r2 = 1588635695, 4294967291, 2, 17054, 44957
    local s1, s2 = math.floor(self._seed / (2^17)), (math.floor(self._seed / 2) % (2^16))
    local p = (r2 * s2) + (2^16) * r1 * s2 + (2^16) * r2 * s1 -- r1 * s1 are MSB and discarded
    self._seed = a*(self._seed % q) - p
    self._seed = self._seed % (2^32)
    return self._seed / m
end