Browse Source

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

Alex Szpakowski 12 years ago
parent
commit
0447d1e7c5

+ 2 - 2
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:

+ 20 - 8
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.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.randomseed(seed);
+		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);
 	}
 
 	/**

+ 9 - 21
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<double>::infinity())

+ 47 - 9
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 = 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
 	{
-		rng_state = seed;
+#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

+ 20 - 21
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";

+ 3 - 2
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);

+ 39 - 25
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
-	{
-		double seed_double;
-		uint64 seed_uint;
-	} s;
+	RandomGenerator::State s;
 
-	s.seed_double = luaL_checknumber(L, idx);
+	if (!lua_isnoneornil(L, idx + 1))
+	{
+		uint32 low = (uint32) luaL_checknumber(L, idx);
+		uint32 high = (uint32) luaL_checknumber(L, idx + 1);
+
+#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<RandomGenerator>(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 }
 };
 

+ 4 - 3
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