Jump to content

Question about math.random / math.randomseed within "generic for loops"


Mordred
 Share

Recommended Posts

Hello fellow Leadwerkers,

 

I'm messing arround as usually. This time i'm trying to get a random function up n running. I did it the easy way for now, to know how it works, but it doesn't work as intended.

 

I might want to say, that i do understand, that math.random is only pseudorandom, i have to shuffle the numbers before i really can use them with "math.randomseed ( os.time())" every time I need a new random seed. Thus no problem. I did use that in another script too and there it did work quite well, but now the following happens.

 

I have a table, in this table several skillrelated items are stored (the table contains the skills "woodcutting" and quarrying, both values again contain several items (logs, bark, twigs....) with an initial value of 0. I now want to iterate this table, check if the "used skill" is within this table and, if it is, i want to increase each value of those items individually. So basically, i have 5 items stored, i want to add a random number to the first one and another random number to the 2nd one. But i always end up that all 5 items do get the exact same number.

 

For a better understanding i gonna add the table and the loop in here. Hopefully, you do understand what i mean. It's sometimes hard to explain myself using english.

 

Table:

Script.xInventory =
{
   woodcutting =
   {
       logs = 0,
       bark = 0,
       twigs = 0,
       leafs = 0,
       insects = 0
   },
   quarrying =
   {
       clay = 0,
       limestone = 0,
       granite = 0,
       basalt = 0,
       obsidian = 0,
       marble = 0,
       quartz = 0
   }
}

 

Script:

  	 for a, b in pairs(self.target.script.inventory.script.xInventory) do
           -- check if the used skill does exists in our table
           if a == self.usedSkill then
               for x, y in pairs(B) do
                   math.randomseed(os.time() + i)
                   ammount = y + math.floor(math.random(0, 1 + (statvalue * (100 + skillvalue) / 1000)))
                   i = i + 10
               end
           end
       end




 

As you can see, i added the math.randomseed(os.time() + i) into the loop. I did add +i (i is plus 10 every loop cycle) to avoid the script using the same time twice, since i already know that os.time() only counts within a second or so. I had the same problem using the "GetSpeed()" function though. Still the "random seed" seems to be always the same.

Link to comment
Share on other sites

Hello Rick,

 

thanks for your reply (again :)). But wouldn't be it so that if i do add the seeding into App.lua that there's a quite high chance to get 2 "math.random(1, 100) in a row generating the same result, or am i wrong? For e.g. to randomize "Skillgains" i actually HAD to use two different seeds to prevent the "Skillains" happen at the same time with the same increasevalue.

Link to comment
Share on other sites

hmm, every call to math.random() should produce a random number. Are you sure your example always gave the same number between 2 different calls, when you did a seed on it only 1 time in your app? I can't test that right now as I'm not at home, but I don't recall seeing that issue with other stuff I did with random. Can you produce a simple example that shows this possible issue?

Link to comment
Share on other sites

Hello Rick,

 

thanks for your reply (again smile.png). But wouldn't be it so that if i do add the seeding into App.lua that there's a quite high chance to get 2 "math.random(1, 100) in a row generating the same result, or am i wrong? For e.g. to randomize "Skillgains" i actually HAD to use two different seeds to prevent the "Skillains" happen at the same time with the same increasevalue.

Random numbers can and will produce the same value twice in a row. The value of the last call has no bearing on the value of the next call...otherwise it wouldn't be random!

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

@ Rick, i gonna try to set smth. up in a few minutes (if i manage to get it up 'n runnin, i'm still new to all that stuff smile.png)

 

@ Josh, i'm refering to this thread

 

"A good* 'seed' is os.time(), but wait a second before calling the function to obtain another sequence! To get nice random numbers use:" http://lua-users.org/wiki/MathLibraryTutorial They mention that you should wait a second between two math.random calls due to the fact that the random seed will be the same within a second. Anyways, i just added a simple, plain, math.randomseed(os.time()) into my app.lua and fired up a simple System:Print(math.random(1, 10) onto the console and had no issues at all, they numbers def. were random, even though i generated them in a "for" loop 10 times in a row. So basically, that means i'm doing smth. wrong.

 

And i'm so stupid....i know what's my problem. In case someone is interested in knowing.

 

I did a loop iterating the table i mentioned before. I than stored the item's value (predefined as "0") into the variable "ammount". I than "end"ed the iteration and started a new one working with that "ammount". I think everybody now knows what my problem is. The vallue in ammount was only the last value i received from the first loop.

 

Basically like this:

for a, b in pairs(self.target.script.inventory.script.xInventory) do
if a == self.usedSkill then
for y, x in pairs (B) do
[b]ammount[/b]= x
end
end
end

for a, b in pairs(self.target.script.inventory.script.xInventory) do
-- check if the used skill does exists in our table
if a == self.usedSkill then
for x, y in pairs(B) do
[b]ammount[/b]= y + math.floor(math.random(0, 1 + (statvalue * (100 + skillvalue) / 1000)))
i = i + 10
end
end
end

 

The solution would be like this:

  	 for a, b in pairs(self.target.script.inventory.script.xInventory) do
           -- check if the used skill does exists in our table
           if a == self.usedSkill then
               for x, y in pairs(B) do
                   ammount = y + math.floor(math.random(0, 1 + (statvalue * (100 + skillvalue) / 1000)))
                   self.target.script.inventory.script.xInventory[a][x] = ammount
                   self.target.script.hud.script.xSkills[self.usedSkill] = skillvalue + self.target.script.hud.script.skillgain
                   self.target.script.hud.script.xStats[self.usedStat] = statvalue + self.target.script.hud.script.statgain
               end
           end
       end

Link to comment
Share on other sites

@Mordred:

 

A pseudo-random number generator like math.random takes a starting number, in this case, (math.randomseed( os.time() ) ), performs mathematical operations on it, then continually applies the algorithm to the last generated number, however while each number in the sequence is seemingly random with regards to the previous ones, the entire sequence is not random at all.

 

math.randomseed(999)
for n = 0, 5 do
num = math.random(9)
Print (num)
end

 

1,9,3,7,7,1 everytime.

 

When you use math.random in a loop, you should always have (math.randomseed( os.time() ) ) outside of the loop, this is because the iterations are executed really fast and it nearly every time re-assigns the same "current time", that results in the same *random* starting number being generated.

 

for n = 0, 5 do
math.randomseed(os.time())
num = math.random(9)
Print (num)
end

 

That gave me 7,7,7,7,7,7

 

You had:

 

local i=0
for n = 0, 5 do
math.randomseed(os.time() + i)
num = math.random(9)
Print (num)
i = i + 10
end

 

but again this produces the same first *random* starting number over and over, the article you link to explains why:

 

This difference is lost when Lua converts the integer returned by rand() into a real number, effectively preserving only the high bits in the result. When you call math.random(1,100) from Lua, the low-bit difference vanishes and you see the same integer result

 

So all you have to do is to take math.randomseed( os.time() ) out of loop and set it only once per application run, if you want to "mix up" the seed each time you run the application try:

 

math.randomseed( tonumber(tostring(os.time()):reverse():sub(1,6)) )

  • Upvote 1

AMD Bulldozer FX-4 Quad Core 4100 Black Edition

2 x 4GB DDR3 1333Mhz Memory

Gigabyte GeForce GTX 550 Ti OC 1024MB GDDR5

Windows 7 Home 64 bit

 

BlitzMax 1.50 • Lua 5.1 MaxGUI 1.41 • UU3D Pro • MessiahStudio Pro • Silo Pro

3D Coat • ShaderMap Pro • Hexagon 2 • Photoshop, Gimp & Paint.NET

 

LE 2.5/3.4 • Skyline UE4 • CE3 SDK • Unity 5 • Esenthel Engine 2.0

 

Marleys Ghost's YouTube Channel Marleys Ghost's Blog

 

"I used to be alive like you .... then I took an arrow to the head"

Link to comment
Share on other sites

Hey Marleys Ghost,

 

thanks for explaining it in such detail. I did missunderstood what was written in that wiki. Now that i did put the "randomseed" into app.lua i do not have any issues at all. Besides, i had a builtin error made by myself too (as stated before). Yet i'm quite sure that my "randomseed" within the loop would work since i changed the seed myself everytime by adding "+i" ontop of the initial value. Or am i wrong with that too?

 

Basically i do understand it as: -

- First run --> randomseed is os.time()

- second run --> randomseed is os.time() + 10

- third run --> randomseed is os.time() + 20

 

and thus the seeds differ?

Link to comment
Share on other sites

and thus the seeds differ?

 

Not by enough:

 

 

This difference is lost when Lua converts the integer returned by rand() into a real number, effectively preserving only the high bits in the result. When you call math.random(1,100) from Lua, the low-bit difference vanishes and you see the same integer result

 

 

EDIT: Plus theres no real benefit to constantly altering the seed

AMD Bulldozer FX-4 Quad Core 4100 Black Edition

2 x 4GB DDR3 1333Mhz Memory

Gigabyte GeForce GTX 550 Ti OC 1024MB GDDR5

Windows 7 Home 64 bit

 

BlitzMax 1.50 • Lua 5.1 MaxGUI 1.41 • UU3D Pro • MessiahStudio Pro • Silo Pro

3D Coat • ShaderMap Pro • Hexagon 2 • Photoshop, Gimp & Paint.NET

 

LE 2.5/3.4 • Skyline UE4 • CE3 SDK • Unity 5 • Esenthel Engine 2.0

 

Marleys Ghost's YouTube Channel Marleys Ghost's Blog

 

"I used to be alive like you .... then I took an arrow to the head"

Link to comment
Share on other sites

Yea, well, that there's no real benefit in doing so is clear now, thanks to your explanations. I actually saw that quote you postet before too but i didn't read it, because it was statet as "OsX and FreeBSD" and since i use windows i didn't bother reading it. Well, maybe i should change my behaviour a bit.

 

Thank you again for pointing me to this :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...