Page 3 of 4

Re: RandomLua Library

Posted: Mon Aug 22, 2011 8:30 pm
by Boolsheet
Yes, it's probably the Lua number type. Lua uses by default a double precision floating-point number and AGen seems to be using a Lua built with single precision floating-point numbers. 32-bit integers loose precision because 32-bit floats only have 22 bits for the significand.

Re: RandomLua Library

Posted: Tue Jan 03, 2012 5:34 pm
by CarSoccerRobots
linux-man, thank you for this library!

We're using it in an upcoming project and it is really quite spiffy for our simple needs. It's the first PRNG implementation in pure Lua we found which doesn't require additional bitwise operation libraries.

Re: RandomLua Library

Posted: Mon Sep 09, 2013 9:31 pm
by posfan12
I'm trying to use these scripts in Lua 4.0. Here's my attempt of doing the translation. Lua 4 doesn't have a "setmetatable" function, so I made a guess at what to do in my case.

Code: Select all

	function lcg(s, r)
		local temp = {}
		function temp:random(a, b)
			local y = mod(self.a * self.x + self.c, self.m)
			self.x = y
			if not a then
				return y / 65536
			elseif not b then
				if a == 0 then
					return y
				else
					return 1 + mod(y, a)
				end
			else
				return a + mod(y, b - a + 1)
			end
		end
		function temp:randomseed(s)
			if not s then
				s = seed()
			end
			self.x = mod(s, 2147483648)
		end
		if r then
			--from Numerical Recipes
			if r == 'nr' then
				temp.a = 1664525
				temp.c = 1013904223
				temp.m = 65536
			--from MVC
			elseif r == 'mvc' then
				temp.a = 214013
				temp.c = 2531011
				temp.m = 65536
			end
		--from Ansi C
		else
			temp.a = 1103515245
			temp.c = 12345
			temp.m = 65536
		end
		temp:randomseed(s)
		return temp
	end

	print("wutwut =" .. lcg(0):random())
	print("wutwut =" .. lcg(0):random())
	print("wutwut =" .. lcg(0):random())
Anyway, the problem is that the script is outputting the same decimal value every time I run it. Is this because I am using the script improperly? What is the proper way of using the script? Thanks!!


Mike

Re: RandomLua Library

Posted: Tue Sep 10, 2013 2:10 am
by davisdude
Actually, Lua does have a setmetatable function: http://www.lua.org/pil/13.html

Re: RandomLua Library

Posted: Tue Sep 10, 2013 3:10 am
by slime
davisdude wrote:Actually, Lua does have a setmetatable function: http://www.lua.org/pil/13.html
metatables got added in Lua 5.0. I'm not sure why anyone would use Lua 4.0 though... Lua 5.0 was released a decade ago. Lua 5.1 seven years ago, and Lua 5.2 two years ago (and unfortunately the online version of PiL is still the first edition, for Lua 5.0.)

Re: RandomLua Library

Posted: Tue Sep 10, 2013 3:18 am
by posfan12
I'm working on a game called Homeworld 2 which was released in 2003 and uses Lua 4.0.

I had another person test my script and it worked OK in Lua 4.0.1, so I am SOL I guess unless someone has a better suggestion... :(

Re: RandomLua Library

Posted: Tue Sep 10, 2013 11:10 am
by Boolsheet
It is not surprising that your script prints the same line three times. You create a new generator every time with the same seed and that will obviously return the same number. Save the table and call random on that a few times.

Code: Select all

local gen = lcg(0)
print("wutwut =" .. gen:random())
print("wutwut =" .. gen:random())
print("wutwut =" .. gen:random())
If you're already aware of that, you might want to check if Homeworld 2 was compiled with a Lua that uses single-precision floating-point numbers. If so, calculations that go over 2^24 will not get the results you want. Here's a function that tests for some formats.

Code: Select all

function TestLuaNumberFormat()
	local dbl = 2 ^ 53
	local flt = 2 ^ 24
	local int32 = 1073741823 * 2 + 1
	local uint32 = 1073741823 * 4 + 3
	local int64 = (1073741823 * 131072 + 131071) * 65536 + 65535
	local uint64 = (1073741823 * 131072 + 131071) * 131072 + 131071

	local fmt
	if dbl ~= dbl - 1 and dbl == dbl + 1 then
		fmt = "double-precision floating-point number"
	elseif flt ~= flt - 1 and flt == flt + 1 then
		fmt = "single-precision floating-point number"
	elseif int32 > 0 and int32 + 1 < 0 then
		fmt = "signed 32-bit integer"
	elseif uint32 > 0 and uint32 + 1 == 0 and uint32 + 2 == 1 then
		fmt = "unsigned 32-bit integer"
	elseif int64 > 0 and int64 + 1 < 0 then
		fmt = "signed 64-bit integer"
	elseif uint64 > 0 and uint64 + 1 == 0 and uint64 + 2 == 1 then
		fmt = "unsigned 64-bit integer"
	end

	if fmt then
		print("Feels like " .. fmt .. ".")
	else
		print("Unkown format.")
	end
end
Edit: Looking at it again, Lua 4.0 does not provide an easy way to change it to single precision. Unless they modified it, it's probably double precision.

Re: RandomLua Library

Posted: Tue Sep 10, 2013 4:55 pm
by posfan12
I ran TestLuaNumberFormat() and got "Feels like single-precision floating-point number".

Re: RandomLua Library

Posted: Tue Sep 10, 2013 6:50 pm
by Boolsheet
Didn't expect that. You can rewrite it a bit to get the same results with single precision.

Code: Select all

function mul16(a, b)
	local a_lo, b_lo = mod(a, 2^8), mod(b, 2^8)
	local a_hi, b_hi = a - a_lo, b - b_lo

	return mod(a_lo * b_lo + mod(a_lo * b_hi, 2^16) + mod(a_hi * b_lo, 2^16) + mod(a_hi * b_hi, 2^16), 2^16)
end

function lcg(s, r)
	local temp = {}
	function temp:random(a, b)
		local y = mod(mul16(self.a, self.x) + self.c, self.m)
		self.x = y
		if not a then
			return y / 65536
		elseif not b then
			if a == 0 then
				return y
			else
				return 1 + mod(y, a)
			end
		else
			return a + mod(y, b - a + 1)
		end
	end
	function temp:randomseed(s)
		if not s then
			s = seed()
		end
		self.x = mod(s, 2147483648)
	end

	-- 'Numerical Recipes' parameters
	temp.a = 26125
	temp.c = 62303
	temp.m = 65536

	temp:randomseed(s)
	return temp
end
No guarantees on the statistical properties! :P

Re: RandomLua Library

Posted: Wed Sep 11, 2013 12:57 pm
by posfan12
This one works! No duplicate values after 10000 iterations.

I just need to figure out how to rewrite all my scripts. Currently I just pass the seeds to whatever functions need them. For instance,

Code: Select all

local my_seed_1 = {977322}

function srandom(seedobj, fVal1, fVal2)
	seedobj[1] = mod(seedobj[1] * 1103515245 + 12345, 4294967296)
	local temp_rand = seedobj[1] / (4294967296 - 1)
	if (fVal2) then
		return floor(fVal1 + 0.5 + temp_rand * (fVal2 - fVal1))
	elseif (fVal1) then
		return floor(temp_rand * fVal1) + 1
	else
		return temp_rand
	end
end

print(srandom(my_seed_1))