Open coyo-t opened 6 months ago
If your own RNG is less performant than GM's, it just means yours is better, or just overly complex. The GM RNG sets the seed at the start (or when randomize() or random_set_seed() is called), and every time you call a random function, it increments a hidden counter by the same amount every time. It performs some calculation using that counter and the seed. Whenever you call randomize() or random_set_seed(), the hidden counter resets. It's a very simplistic RNG. Just using something like get_timer() & 15 will give you a fairly random 1:16 chance with minimal processing power. I support GM adding a secondary set of RNG, though.
errr,... the random number generator is nothing like the description above it is a full psuedo random number generator an implementation of https://web.archive.org/web/20181215122620/http://www.lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf
the random seed is changed as part of the algorithm (ready for the next iteration)
randomize just choses a random seed.
other reading http://stackoverflow.com/questions/1046714/what-is-a-good-random-number-generator-for-a-game
the full C++ code we use is (we have published this before)
unsigned int YYRandom( void )
{
// return ((float)rand() * (1.0f/((float)RAND_MAX+1.0f)));
// PRNG from http://www.lomont.org/Math/Papers/2008/Lomont_PRNG_2008.pdf
// other reading http://stackoverflow.com/questions/1046714/what-is-a-good-random-number-generator-for-a-game
unsigned int a, b, c, d;
a = state[g_RndIndex];
c = state[(g_RndIndex+13)&15];
b = a^c^(a<<16)^(c<<15);
c = state[(g_RndIndex+9)&15];
c ^= (c>>11);
a = state[g_RndIndex] = b^c;
d = a^((a<<5)&s_nRandomPoly);
g_RndIndex = (g_RndIndex + 15)&15;
// RK :: clang had an optimisation bug, caused when the following lines used to be
// RK :: a = state[g_RndIndex];
// RK :: state[g_RndIndex] = a^b^d^(a<<2)^(b<<18)^(c<<28);
// RK :: where it seemed to think that it was OK to take d and substitiute in a^((a<<5)&s_nRandomPoly); into the expr a^b^d^(a<<2)^(b<<18)^(c<<28)
// RK :: but a had been changed completely by the time that expr happened so it got the wrong answer
// RK :: originally we switched off optimisations on this file (but that cannot be done reliably on all build systems, so changing this
// RK :: to a different volatile variable seems to work
volatile unsigned int e = state[g_RndIndex];
state[g_RndIndex] = e^b^d^(e<<2)^(b<<18)^(c<<28);
return state[g_RndIndex];
}
Is your feature request related to a problem?
its not easy to have fine control over RNG in gamemaker. you cant get the current RNG state or push/pop it; you can only get and set the original seed in addition to it being one global RNG state. this is a problem if the current random state needs to be saved for a later time (IE level gen, but some graphical stuff needs random numbers too, which shouldnt affect the levelgen outcome. or demo playback which needs the exact random state to play back the demo without desyncs)
Describe the solution you'd like
functions which create a random "object"/"state" (
random_create(seed)
,random_destroy(rng)
). as well, a function that takes a random object and makes it the current global random state (random_get_state()
random_set_state(rng)
). this way the existingrandom_*
funcs would be kept in-place as they are without needing to change them to take in a random objectDescribe alternatives you've considered
creating my own rng structs based on Java's. while this "works" im not happy with it (obviously not as performant as the native random functions, less portable across projects, ect)
Additional context
No response