Better random function

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.

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


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().

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[1] then
            pot[1] = pot[1] + 1
        else
            pot[1] = 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

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

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…:slight_smile:

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.

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

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