Bug In Renoise/Lua Math.Random Library?


(Conner_Bw) #1

On OSX, if I run this code 50 times:

  
math.randomseed(os.time())  
local test = {"a", "b", "c", "d", "e", "f", "g"}  
for i = 1, 5 do  
 prefix = math.random(1, #test)  
 prefix = test[prefix]  
 print(prefix)  
end  
print("---")  
  

The first value is always “a”

This is wrong, I expect the first value to be random.

If I remove math.randomseed(os.time()) it works as expected.

What is going on?


New Tool: (3.1) Random Plug (Feb 2019)
New Tool: (3.1) Random Plug (Feb 2019)
How To Set Bpm Back To "Random-On-Start"?
(dblue) #2

When you call math.randomseed() then (I assume) you are resetting the seed of the random number generator. When you reset the seed to a specific number, then the number generator will output the same, predictable sequence of pseudo-random numbers every time. I think the problem here stems from the os.time() function, which is not accurate enough to give you a unique value every single time you call it (within such a short amount of time).

For example:

for i = 1, 50 do  
 print(os.time())  
end  

This will (probably) output the same value for all 50 iterations, because the result of the os.time() function simply isn’t accurate enough to produce a different value each time it is called in this way.

Something like this might work a bit better:

math.randomseed(os.time())  
local test = {"a", "b", "c", "d", "e", "f", "g"}  
for x = 1, 50 do  
 for i = 1, 5 do  
 prefix = math.random(1, #test)  
 prefix = test[prefix]  
 print(prefix)  
 end  
 print("---")  
end  

You only need to call math.randomseed() once per session.


(Conner_Bw) #3

Yes, I understand what a random seed is, maybe you were explaining this for the benefit of other, but the behaviour is wrong.

If I run your code 50 times, i’ll get 250 prints, but the first print is always “a”. (Actually, now it’s always “b” because the seed is a bit higher, let’s rephrase that to “first value is always the same”)

Let’s look at it differently, here are two different values of os.time()

1283628570
1283629982

Run this code:

  
local test = {"a", "b", "c", "d", "e", "f", "g"}  
  
math.randomseed(1283628570)  
for i = 1, 5 do  
 prefix = math.random(1, #test)  
 prefix = test[prefix]  
 print(prefix)  
end  
print("---")  
  
math.randomseed(1283629982)  
for i = 1, 5 do  
 prefix = math.random(1, #test)  
 prefix = test[prefix]  
 print(prefix)  
end  
print("---")  
  

Notice that the first value of both are identical.

Either the seeds are being truncated, or os.time() is a terrible seed due to the way Lua works and I need something better.

-=-=-

Actually, I just googled it, and it may be OSX specific.

All spelling mistakes are final and will not be refunded.


(Conner_Bw) #4

A good explanation of my problem, here:

http://lua-users.org/lists/lua-l/2007-03/msg00564.html

The tip I will probably use for my code:

Just to empty the buffer, so to speak.


(dblue) #5

I apologise if anything sounded condescending, because that was definitely not my intention at all. I realise that you are an intelligent dude, but not everyone is quite so nerdy to understand pseudo-random number generators! I thought I would mention it, just in case. :)

The output I get (from Windows XP) is:

  
c  
c  
d  
g  
e  
---  
d  
d  
b  
g  
a  
---  
  

… so you could be right here, and this may be an OSX problem.

Hrm!


(Conner_Bw) #6

This works for me:

  
 math.randomseed(os.time())  
 local garbage = math.random()  
 garbage = math.random()  
 -- Back to normal  
  

Calling math.random() a couple of times before actually using avoids blatant similarities.


(Conner_Bw) #7

Works for me in the context of NotesRandomizer on OSX.

My problem was identical values, i think the discussion on that wiki page is about “true randomness”, but for my script i’m happy to live with “fake” over “not random” ;)


(vV) #8

I already experienced this problem long time ago…
I solved it this way back then:

  
function randomize(tstart, tend)  
 local number = tostring(os.clock())  
 if string.find(number,"%.") ~= nil then  
 number = string.sub(number, string.find(number,"%.")+1)  
 end  
 math.randomseed( tonumber(number))  
 number = number + math.random(1, 7)  
 math.randomseed( tonumber(number))  
 math.random(tstart, tend); math.random(tstart, tend); math.random(tstart, tend)  
 local result = math.random(tstart, tend)  
 return result  
end  
  

When looking at it again… i guess the whole monkeybusiness before the three math.random(tstart, tend) calls seem measures in vain as calling this function three times most likely was enough…