From 0447d1e7c585db2d55bd07178fb4d940deddb79d Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 1 Aug 2013 18:32:44 -0300 Subject: [PATCH] Changed love.math.randomnormal([mean], stddev) to love.math.randomNormal(stddev, [mean]); Changed love.math.randomseed(seed) to love.math.setRandomState(state) and love.math.setRandomState(low, high). Added low, high = love.math.getRandomState(). love.math.setRandomState(state) can set the random state to an integer of up to 53 bits, love.math.setRandomState(low, high) can set the random state to a 64 bit integer by using the first argument as the lower 32 bits and the second argument as the higher 32 bits. This allows for reliable setting and saving of the state of a RNG. --HG-- branch : RandomGenerator-2 --- .../graphics/opengl/ParticleSystem.cpp | 4 +- src/modules/math/MathModule.h | 28 ++++++--- src/modules/math/RandomGenerator.cpp | 30 +++------ src/modules/math/RandomGenerator.h | 56 ++++++++++++++--- src/modules/math/wrap_Math.cpp | 41 ++++++------ src/modules/math/wrap_Math.h | 5 +- src/modules/math/wrap_RandomGenerator.cpp | 62 ++++++++++++------- src/modules/math/wrap_RandomGenerator.h | 7 ++- 8 files changed, 143 insertions(+), 90 deletions(-) diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index c6c99fa00..2b1d787b8 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -217,8 +217,8 @@ void ParticleSystem::initParticle(particle *p) p->position[1] += (float) rng.random(-areaSpread.getY(), areaSpread.getY()); break; case DISTRIBUTION_NORMAL: - p->position[0] += (float) rng.randomnormal(areaSpread.getX()); - p->position[1] += (float) rng.randomnormal(areaSpread.getY()); + p->position[0] += (float) rng.randomNormal(areaSpread.getX()); + p->position[1] += (float) rng.randomNormal(areaSpread.getY()); break; case DISTRIBUTION_NONE: default: diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index 51cb062ba..01af49fdc 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -53,12 +53,24 @@ public: virtual ~Math() {} - /** - * @copydoc RandomGenerator::randomseed() - **/ - inline void randomseed(uint64 seed) + inline void setRandomState(RandomGenerator::State state) { - rng.randomseed(seed); + rng.setState(state); + } + + inline void setRandomState(uint32 low, uint32 high) + { + rng.setState(low, high); + } + + inline RandomGenerator::State getRandomState() const + { + return rng.getState(); + } + + inline void getRandomState(uint32 &low, uint32 &high) const + { + rng.getState(low, high); } /** @@ -86,11 +98,11 @@ public: } /** - * @copydoc RandomGenerator::randomnormal() + * @copydoc RandomGenerator::randomNormal() **/ - inline double randomnormal(double stddev) + inline double randomNormal(double stddev) { - return rng.randomnormal(stddev); + return rng.randomNormal(stddev); } /** diff --git a/src/modules/math/RandomGenerator.cpp b/src/modules/math/RandomGenerator.cpp index 55f9c24aa..fd27bdcc8 100644 --- a/src/modules/math/RandomGenerator.cpp +++ b/src/modules/math/RandomGenerator.cpp @@ -36,37 +36,25 @@ RandomGenerator::RandomGenerator() { // because it is too big for some compilers to handle ... if you know what // i mean - union - { - uint64 b64; - struct - { - uint32 a; - uint32 b; - } b32; - } converter; - #ifdef LOVE_BIG_ENDIAN - converter.b32.a = 0x0139408D; - converter.b32.b = 0xCBBF7A44; + rng_state.b32.a = 0x0139408D; + rng_state.b32.b = 0xCBBF7A44; #else - converter.b32.b = 0x0139408D; - converter.b32.a = 0xCBBF7A44; + rng_state.b32.b = 0x0139408D; + rng_state.b32.a = 0xCBBF7A44; #endif - - rng_state = converter.b64; } uint64 RandomGenerator::rand() { - rng_state ^= (rng_state << 13); - rng_state ^= (rng_state >> 7); - rng_state ^= (rng_state << 17); - return rng_state; + rng_state.b64 ^= (rng_state.b64 << 13); + rng_state.b64 ^= (rng_state.b64 >> 7); + rng_state.b64 ^= (rng_state.b64 << 17); + return rng_state.b64; } // Box–Muller transform -double RandomGenerator::randomnormal(double stddev) +double RandomGenerator::randomNormal(double stddev) { // use cached number if possible if (last_randomnormal != std::numeric_limits::infinity()) diff --git a/src/modules/math/RandomGenerator.h b/src/modules/math/RandomGenerator.h index f28aebf2c..ae0975c24 100644 --- a/src/modules/math/RandomGenerator.h +++ b/src/modules/math/RandomGenerator.h @@ -22,6 +22,7 @@ #define LOVE_MATH_RANDOM_GENERATOR_H // LOVE +#include "common/config.h" #include "common/math.h" #include "common/int.h" #include "common/Object.h" @@ -38,19 +39,56 @@ class RandomGenerator : public Object { public: - RandomGenerator(); + union State + { + uint64 b64; + struct + { + uint32 a; + uint32 b; + } b32; + }; - virtual ~RandomGenerator() {}; + RandomGenerator(); + virtual ~RandomGenerator() {} /** - * Set pseudo random seed. + * Set pseudo-random state. * It's up to the implementation how to use this. - * - * @param seed The random seed. **/ - inline void randomseed(uint64 seed) + inline void setState(State state) { - rng_state = seed; + rng_state = state; + } + + /** + * Separately set the low and high parts of the pseudo-random state. + **/ + inline void setState(uint32 low, uint32 high) + { +#ifdef LOVE_BIG_ENDIAN + rng_state.b32.a = high; + rng_state.b32.b = low; +#else + rng_state.b32.b = high; + rng_state.b32.a = low; +#endif + } + + inline State getState() const + { + return rng_state; + } + + inline void getState(uint32 &low, uint32 &high) const + { +#ifdef LOVE_BIG_ENDIAN + high = rng_state.b32.a; + low = rng_state.b32.b; +#else + high = rng_state.b32.b; + low = rng_state.b32.a; +#endif } /** @@ -96,11 +134,11 @@ public: * @param stddev Standard deviation of the distribution. * @return Normally distributed random number with mean 0 and variance (stddev)². **/ - double randomnormal(double stddev); + double randomNormal(double stddev); private: - uint64 rng_state; + State rng_state; double last_randomnormal; }; // RandomGenerator diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index fa901ef56..2dc520446 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -32,32 +32,32 @@ namespace love namespace math { -int w_randomseed(lua_State *L) +int w_setRandomState(lua_State *L) { - uint64 seed = luax_checkrandomseed(L, 1); - Math::instance.randomseed(seed); + Math::instance.setRandomState(luax_checkrandomstate(L, 1)); return 0; } +int w_getRandomState(lua_State *L) +{ + uint32 low = 0, high = 0; + Math::instance.getRandomState(low, high); + lua_pushnumber(L, (lua_Number) low); + lua_pushnumber(L, (lua_Number) high); + return 2; +} + int w_random(lua_State *L) { return luax_getrandom(L, 1, Math::instance.random()); } -int w_randomnormal(lua_State *L) +int w_randomNormal(lua_State *L) { - double mean = 0.0, stddev = 1.0; - if (lua_gettop(L) > 1) - { - mean = luaL_checknumber(L, 1); - stddev = luaL_checknumber(L, 2); - } - else - { - stddev = luaL_optnumber(L, 1, 1.); - } + double stddev = luaL_optnumber(L, 1, 1.0); + double mean = luaL_optnumber(L, 2, 0.0); + double r = Math::instance.randomNormal(stddev); - double r = Math::instance.randomnormal(stddev); lua_pushnumber(L, r + mean); return 1; } @@ -67,10 +67,7 @@ int w_newRandomGenerator(lua_State *L) RandomGenerator *t = Math::instance.newRandomGenerator(); if (lua_gettop(L) > 0) - { - uint64 seed = luax_checkrandomseed(L, 1); - t->randomseed(seed); - } + t->setState(luax_checkrandomstate(L, 1)); luax_newtype(L, "RandomGenerator", MATH_RANDOM_GENERATOR_T, (void *) t); return 1; @@ -264,9 +261,10 @@ int w_noise(lua_State *L) // List of functions to wrap. static const luaL_Reg functions[] = { - { "randomseed", w_randomseed }, + { "setRandomState", w_setRandomState }, + { "getRandomState", w_getRandomState }, { "random", w_random }, - { "randomnormal", w_randomnormal }, + { "randomNormal", w_randomNormal }, { "newRandomGenerator", w_newRandomGenerator }, { "newBezierCurve", w_newBezierCurve }, { "triangulate", w_triangulate }, @@ -285,6 +283,7 @@ static const lua_CFunction types[] = extern "C" int luaopen_love_math(lua_State *L) { Math::instance.retain(); + WrappedModule w; w.module = &Math::instance; w.name = "math"; diff --git a/src/modules/math/wrap_Math.h b/src/modules/math/wrap_Math.h index 63b61abd5..734e46403 100644 --- a/src/modules/math/wrap_Math.h +++ b/src/modules/math/wrap_Math.h @@ -30,9 +30,10 @@ namespace love namespace math { -int w_randomseed(lua_State *L); +int w_setRandomState(lua_State *L); +int w_getRandomState(lua_State *L); int w_random(lua_State *L); -int w_randomnormal(lua_State *L); +int w_randomNormal(lua_State *L); int w_newRandomGenerator(lua_State *L); int w_newBezierCurve(lua_State *L); int w_triangulate(lua_State *L); diff --git a/src/modules/math/wrap_RandomGenerator.cpp b/src/modules/math/wrap_RandomGenerator.cpp index 126ff7c6f..46674209f 100644 --- a/src/modules/math/wrap_RandomGenerator.cpp +++ b/src/modules/math/wrap_RandomGenerator.cpp @@ -27,17 +27,27 @@ namespace love namespace math { -uint64 luax_checkrandomseed(lua_State *L, int idx) +RandomGenerator::State luax_checkrandomstate(lua_State *L, int idx) { - union + RandomGenerator::State s; + + if (!lua_isnoneornil(L, idx + 1)) { - double seed_double; - uint64 seed_uint; - } s; + uint32 low = (uint32) luaL_checknumber(L, idx); + uint32 high = (uint32) luaL_checknumber(L, idx + 1); - s.seed_double = luaL_checknumber(L, idx); +#ifdef LOVE_BIG_ENDIAN + s.b32.a = high; + s.b32.b = low; +#else + s.b32.b = high; + s.b32.a = low; +#endif + } + else + s.b64 = (uint64) luaL_checknumber(L, idx); - return s.seed_uint; + return s; } int luax_getrandom(lua_State *L, int startidx, double r) @@ -71,45 +81,49 @@ RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx) return luax_checktype(L, idx, "RandomGenerator", MATH_RANDOM_GENERATOR_T); } -int w_RandomGenerator_randomseed(lua_State *L) +int w_RandomGenerator_setState(lua_State *L) { RandomGenerator *rng = luax_checkrandomgenerator(L, 1); - uint64 seed = luax_checkrandomseed(L, 2); - rng->randomseed(seed); + rng->setState(luax_checkrandomstate(L, 2)); return 0; } +int w_RandomGenerator_getState(lua_State *L) +{ + RandomGenerator *rng = luax_checkrandomgenerator(L, 1); + + uint32 low = 0, high = 0; + rng->getState(low, high); + + lua_pushnumber(L, (lua_Number) low); + lua_pushnumber(L, (lua_Number) high); + return 2; +} + int w_RandomGenerator_random(lua_State *L) { RandomGenerator *rng = luax_checkrandomgenerator(L, 1); return luax_getrandom(L, 2, rng->random()); } -int w_RandomGenerator_randomnormal(lua_State *L) +int w_RandomGenerator_randomNormal(lua_State *L) { RandomGenerator *rng = luax_checkrandomgenerator(L, 1); - double mean = 0.0, stddev = 1.0; - if (lua_gettop(L) > 2) - { - mean = luaL_checknumber(L, 2); - stddev = luaL_checknumber(L, 3); - } - else - { - stddev = luaL_optnumber(L, 2, 1.0); - } + double stddev = luaL_optnumber(L, 2, 1.0); + double mean = luaL_optnumber(L, 3, 0.0); + double r = rng->randomNormal(stddev); - double r = rng->randomnormal(stddev); lua_pushnumber(L, r + mean); return 1; } static const luaL_Reg functions[] = { - { "randomseed", w_RandomGenerator_randomseed }, + { "setState", w_RandomGenerator_setState }, + { "getState", w_RandomGenerator_getState }, { "random", w_RandomGenerator_random }, - { "randomnormal", w_RandomGenerator_randomnormal }, + { "randomNormal", w_RandomGenerator_randomNormal }, { 0, 0 } }; diff --git a/src/modules/math/wrap_RandomGenerator.h b/src/modules/math/wrap_RandomGenerator.h index a2fe347b0..43e1eab15 100644 --- a/src/modules/math/wrap_RandomGenerator.h +++ b/src/modules/math/wrap_RandomGenerator.h @@ -32,13 +32,14 @@ namespace math { // Helper functions. -uint64 luax_checkrandomseed(lua_State *L, int idx); +RandomGenerator::State luax_checkrandomstate(lua_State *L, int idx); int luax_getrandom(lua_State *L, int startidx, double r); RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx); -int w_RandomGenerator_randomseed(lua_State *L); +int w_RandomGenerator_setState(lua_State *L); +int w_RandomGenerator_getState(lua_State *L); int w_RandomGenerator_random(lua_State *L); -int w_RandomGenerator_randomnormal(lua_State *L); +int w_RandomGenerator_randomNormal(lua_State *L); extern "C" int luaopen_randomgenerator(lua_State *L); } // math