#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# Better random function

edited January 2013 in General Posts: 58

Is there any way to create a 'more random', random number than the number generated by math.random()? Too many times I've gotten the same number too many times in a row for my liking (5 or 6), and was wondering if anyone else had come up with another way of creating a better random number.

Tagged:

• Posts: 791

I think the random number generator is perfectly acceptable. The following simple program shows a count over time how often each number has been generated and also logs the maximum number of times in a row a number has been generated. Change the parameter max to set your maximum value. On this evidence there doesn't appear to be a bias towards any number. Perhaps if you posted your code which was causing the issue?

``````-- random

-- Use this function to perform your initial setup
function setup()
supportedOrientations(LANDSCAPE_ANY)
displayMode(FULLSCREEN)
max=10
num={}
for i=1,max do
num[i]=0
end
total=0
timesinarow=0
timesinarowmax=0
lastnum=0
textAlign(LEFT)
textMode(CORNER)
end

-- This function gets called once every frame
function draw()
-- This sets a dark background color
background(40, 40, 50)

-- This sets the line thickness
strokeWidth(5)
local rnum=math.random(max)
num[rnum] = num[rnum] + 1
if rnum==lastnum then
timesinarow = timesinarow + 1
if timesinarow>timesinarowmax then
timesinarowmax=timesinarow
end
else
timesinarow=0
end
lastnum=rnum
for i=1,max do
text(i..":"..num[i],40,400+i*20)
rect(100,400+i*20,100+num[i],18)
end
text("X:"..timesinarow,60,300)
rect(100,300,100+timesinarow*10,18)
text("Max number of repeats:"..timesinarowmax,40,250)
end

``````
• Posts: 489

Hello @edat44. I understand that Lua's `math.random()` function makes use of C's `rand()` function from `stdlib.h`. I also understand that the algorithm underlying `rand()` is not itself part of the C standard, and can vary.

There are articles on the Internet that criticise what `rand()` produces for some types of use. However, I agree with @West that a first step in your case would be to examine how you are using `math.random()`.

• edited January 2013 Posts: 489

A little code modelling consecutive throws of a six-sided die (update: amended to report expected number of sequences too):

```--
-- Die Die Die
--

function setup()
local nThrows = 1000000 -- One million throws
local pot = {} -- Will hold the counts
local seqCount = 0 -- Number of sequences
local oldThrow = math.random(6) -- First throw
local seqLen = 1
for i = 1, nThrows - 2 do
local newThrow = math.random(6)
if newThrow == oldThrow then
seqLen = seqLen + 1
else
if pot[seqLen] then
pot[seqLen] = pot[seqLen] + 1
else
pot[seqLen] = 1
end
seqLen = 1 -- Reset sequence length
seqCount = seqCount + 1
end
oldThrow = newThrow
end
local newThrow = math.random(6) -- Last throw
if newThrow == oldThrow then
seqLen = seqLen + 1
else
seqCount = seqCount + 1
if pot then
pot = pot + 1
else
pot = 1
end
end
if pot[seqLen] then
pot[seqLen] = pot[seqLen] + 1
else
pot[seqLen] = 1
end
seqCount = seqCount + 1
print("Number of throws:", string.format("%d", nThrows))
print("Expected number of sequences: ", string.format("%d",
1 + (nThrows - 1) * 5/6))
print("Actual number of sequences: ", string.format("%d", seqCount))
for seqLen, nSeq in pairs(pot) do
local rate = string.format("%7.4f%%", nSeq/seqCount * 100)
local odds = string.format("1 in %.2f", seqCount / nSeq)
print(seqLen..":", rate, odds)
end
end

function draw() background(0) end
```
• edited January 2013 Posts: 8,625

Here is something I wrote long ago to check the random numbers. It seemed to show a good enough distribution for my needs. If numbers are truly random, there isn't anything that says you can't have the same number multiple times in a row. Can anything be truly random, everything is always influenced by something else. The human mind will always find patterns in something and think that it can't be random.

``````function setup()
displayMode(FULLSCREEN)
img=image(WIDTH,HEIGHT)
end

function draw()
x=math.random(WIDTH)
y=math.random(HEIGHT)
img:set(x,y,255,255,255)
sprite(img,WIDTH/2,HEIGHT/2)
end

``````
• edited January 2013 Posts: 398

I've never had a problem with math.random - certainly for coding under Lua, its more than adequate, although unsure what algorithm it uses.

You may wish to look at others if this really is an issue - such as the popular 'Mersenne Twister' which is used by Python (amongst others) and is generally accepted as being one of the better ones for generating a robust stream of pseudo-random numbers, albeit being completely deterministic. Wikilink and pseudo-code is here:

http://en.wikipedia.org/wiki/Mersenne_twister

Also, I've had some good experience at using noise(). (Which is based on Perlin noise) to generate random numbers providing you use a large step between samples.

Hope this helps..:-)

• Posts: 489

I read somewhere (here) that iOS/Objective-C may use:

x = (7^5 * x) mod (2^31 - 1)

for its sequence of pseudo-random numbers.

• Posts: 58

I guess now that I look back at my code, all my random numbers I used had a very close minimum and maximum value. As I increased this range, the numbers repeated themselves less often and felt more random (as makes sense). I guess I just wasn't thinking and for some reason expected every other time the funciton is called to produce something different, but as I think about it now, as dave1707 said,
'there isn't anything that says you can't have the same number multiple times in a row'
Thanks to all who posted, It helped clear up my mind some, and my program now makes i little more sense

• Posts: 8,625

One way to determine if the random() function is giving a good sample is to compare it to the Monte Carlo calculation of Pi. Here is an example. Using random numbers, Pi can be calculated by the ratio of points in a circle to the total points in a square the size of the circle. The formula for Pi is, the number of points in the circle divided by the number of points in the square, times 4. The closer the calculated value of Pi to the actual value of Pi, the better the sample calculated by the random() function. This example has to run a long time to get a good sample. A faster calculation can be done by removing the graphics and putting the calculations in a for loop in the setup() function.

``````displayMode(FULLSCREEN)
supportedOrientations(PORTRAIT)

function setup()
w=WIDTH
w2=w/2
ww=w*w
img=image(w,w)
total=0
inside=0
end

function draw()
background(40,40,50)
sprite(img,w2,w2+100)

-- total points
total = total + 1

-- draw circle
stroke(255)
strokeWidth(1)
noFill()
ellipse(w2,w2+100,w)

-- draw square
rectMode(CENTER)
rect(w2,w2+100,w,w)

-- get random x,y values
x=math.random(w)
y=math.random(w)

-- draw points on image
fill(255)
img:set(x,y,255,255,255,255)

-- is x,y on or inside the circle
if x*x+y*y<=ww then
inside = inside + 1
end

text("Monte Carlo Pi",380,990)
text("Pi = ( inside / total ) * 4",380,930)
str=string.format("inside %d   total %d",inside,total)
text(str,380,960)
str=string.format("Pi %f",inside/total*4)
text(str,380,900)
end

``````