math.Random Help

Im using math.random to randomly select a string from a table but it isn’t always 100% random, How would i go about making it 100% random so it doesn’t chose the same string two times in a row.

I’m using a setup similar to this:




local x = math.random( 1, 10 )

print( x )



My problem is that ill get the same thing printed twice, eg. 2 and 2. I’ve thought about somehow storing the last number but i can’t figure out how to do that.

-snip-

Sorry but i don’t see how that will fix my problem, maybe if you could explain. Also i only want the code to run once not evey tick.

table[math.random(0, 10)] would be the only way to get a true random every time, unless you call a function and re-define the variable each time it is called.

You can reset the seed if you want.

:snip: code wouldn’t work properly

If it choses the same number twice in a row, that doesn’t mean it isn’t completely random. You can throw a dice twice and get the same number… But if you want to avoid this, you could try inserting your options into a table. Then generate a random number between 1 and the table size, and remove the chosen one. Just remember to reinsert it after that.

Edit: Also, you could store the last chosen number into a variable, and the next time you send math.Random(), check if its the same as the last one. If that’s the case, execute math.Random() again inside a while loop (LUA has while loops, right?). It should return a different number. Just make sure you don’t make an endless loop.

[lua]
math.randomseed(os.time())
local x = math.random(1, 10)

print(x)
[/lua]

I think this will make it 100% random.

Here’s an amazing resource over the math library in Lua:

However, I agree with MaxShadow. You won’t always get different numbers. Especially with only 10 numbers. Now if you had around five-thousand numbers and you had two numbers in a role be the same I’d understand. But even then, it can STILL happen.

Two numbers being the same is totally coincidental, when getting random numbers.

Technically, you can also revise your script to the following:

Having only one argument will have a random number from 1 and number. So there’s no point in having both of those arguments you had, really.

[lua]
math.randomseed(os.time())
local x = math.random(10)

print(x)
[/lua]

I’m pretty sure the randomseed is set as os.time() by default- I don’t think you need to set it as the same thing twice

[editline]19th March 2016[/editline]

I suppose you could try something like this if you didn’t want the randomly generated number to repeat:



local cached -- this variable is used to cache the previously generated number

local function RandomNoRepeat( low, high )
   local rand = math.random( low, high ) -- get a random number between the low and high values
   if rand == cached then -- if the randomly generated number is the same as the last
      if rand + 1 > high then -- check if adding 1 would make it over the limit
          rand = rand - 1 -- if it would, then take away 1
          else -- if it wouldn't
          rand = rand + 1 -- add one instead
      end
   end
   cached = rand -- set the cached number as the (possibly altered) random number
   return rand -- return it
end


(Not quite sure if this function would work properly since I haven’t tested it, but as long as the high and low numbers aren’t the same it should work)

Then you could just do



sometable[RandomNoRepeat(1,10)]


To get a non-repeated random number - except this number wouldn’t really be random any more since it doesn’t repeat…

Also, there’s always a chance of that function returning something like 1, then 2, then 1 again and so on

I decided to write a mt19937 implementation in Lua after I`ve seen this thread.

[lua]
local k_MTLength = 624
local k_BitMask32 = 0x00000000ffffffff
local k_BitPow31 = bit.lshift(1, 31)

local function printhex(d)
print(string.format("%08x", d))
end

local function mul(a, b, maxBits)

local res = 0
local negative = (a < 0 and b > 0) or (a > 0 and b < 0)

a = math.abs(a)
b = math.abs(b)

for i = 0, maxBits - 1 do
	local mask = bit.lshift(1, i)
	local bitV = bit.band(b, mask)
	if bitV > 0 then
		res = res + (bit.lshift(a, i))
	end
end

if negative then
	res = bit.bnot(res) + 1
end

return res

end

local function add(a, b, maxBits)

local res = 0
local c = 0

for i = 0, maxBits - 1 do
	local mask = bit.lshift(1, i)
	local b1 = bit.rshift(bit.band(a, mask), i)
	local b2 = bit.rshift(bit.band(b, mask), i)
	local v = bit.bxor(bit.bxor(b1, b2), c)
	c = bit.bor(bit.bor(bit.band(b2, c), bit.band(b1, b2), bit.band(b1, c)))
	res = bit.bor(res, bit.lshift(v, i))
end

return res

end

local mt19937_meta = {}

function mt19937_meta:init(seed)

self.KeyTable = {}
self.KeyTable[0] = 0
self.State = 0
self:seed(seed)

end

function mt19937_meta:seed(seed)

self.KeyTable[0] = seed
self.State = 0

for i = 1, k_MTLength - 1 do
	local shift = bit.rshift(self.KeyTable[i - 1], 30)
	local xored = bit.bxor(self.KeyTable[i - 1], shift)
	local entry = add(mul(1812433253, xored, 32), i, 32)
	self.KeyTable* = entry
end

end

function mt19937_meta:get(min, max)

min = min or 0
max = max or 0xFFFFFFFF

if self.State == 0 then

	for i = 0, k_MTLength - 1 do
		local y = add(
			bit.band(self.KeyTable*, k_BitPow31),
			bit.band(self.KeyTable[(i + 1) % k_MTLength], k_BitPow31 - 1),
			32)
		self.KeyTable* = bit.bxor(self.KeyTable[(i + 397) % k_MTLength], bit.rshift(y, 1));
		if y % 2 > 0 then
			self.KeyTable* = bit.bxor(self.KeyTable*, 2567483615)
		end
	end

end

local res = self.KeyTable[self.State]

res = bit.bxor(res, bit.rshift(res, 11))
res = bit.bxor(res, bit.band(bit.lshift(res, 7), 0x000000009D2C5680))
res = bit.bxor(res, bit.band(bit.lshift(res, 15), 0x00000000EFC60000))
res = bit.bxor(res, bit.rshift(res, 18))

self.State = (self.State + 1) % k_MTLength

return min + ((res % max) - min)

end

mt19937_meta.__index = mt19937_meta

function mt19937(seed)

seed = seed or 0

local new = {}
setmetatable(new, mt19937_meta)

new:init(seed)
return new

end
[/lua]

The performance isn’t perfect due the manual add/mul, I had to account the overflow of uint32_t in order to have a deterministic implementation that would work along with the default implementation.

[lua]
local mt = mt19937(os.clock())
for i = 0, 10 do
print(mt:get(0, 10))
end
[/lua]

It should give some good results, see blow:



8
4
6
0
8
9
9
2
7
0
6


Oh fuck, really? I didn’t know that. Thanks for the info. I’ll have to remember that.

what is the bloatware in this thread? I am so confused.

[lua]local old, new
function NonRepeatingRandom(min, max)
local i = 0
while (old == new) and (i < 100) do
new = math.random(min, max)
i = i + 1
end

old = new
return new

end[/lua]

This tries 100 times to give you a new random number that’s different from the previous one. If it gets the same number 100 times in a row, it just gives up and returns that one, but that shouldn’t happen unless you gave it min and max that are identical.

Edit: to clarify, it is plausible to get the same number 100 times in a row in a truly random environment, but pseudo-random algorithms don’t tend to do that.

Man, that’s completely unnecessary… GLua already has a function to return random numbers. Also, your function returns 9 twice, so it is not solving the OP’s problem.

The function MPan1 posted should work fine. It will always return the next number if its the same as the last one (unless that number is the maximum).

I’m aware, just did it for the fun, perhaps it might gives one some insight on how those things work.

by definition, the number returned is therefore not random.

While we’re stating random facts, I’d like to mention that your avatar always has the same rings passing the same balls - that is, each ball only ever goes through one ring. Also, each ball and ring makes exactly one rotation for every animation loop, rather than 1/5 more or 1/5 less etc. As far as gifs go, it’s fairly disappointing.

As for the randomness, we surely can discuss the true definition of randomness and you are right of course in saying that a truly random system does allow for repetitions, but that doesn’t do anything to help – clearly OP needs a non-repeating RNG, regardless of whether it’s “truly random” or not.

You could claim that this could educate him, and yes it could, but the way you phrased it doesn’t really seem to point in that direction.

Rekt by a slice of cheese drawn in MS Paint

Don’t associate me with those sliced hooligans. I’m a full block, unsliced and ungrated. Classy.

You have 4 holes in you

Also you’re clearly not a full block you cheap peasant

How dare you bring up my bullet wounds!