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:

Comments

  • 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[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
    
  • dave1707dave1707 Mod
    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

  • dave1707dave1707 Mod
    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
Sign In or Register to comment.