7

How can I use randomize and rnd to get a repeating list of random variables?

By repeating list, I mean if you run a loop to get 10 random numbers, each random number in the list will be unique. In addition, if you were to run this sequence again, you would get the same 10 random numbers as before.

paxdiablo
  • 772,407
  • 210
  • 1,477
  • 1,841
sooprise
  • 20,955
  • 62
  • 180
  • 265

2 Answers2

18

From Microsoft's own mouth:

To repeat sequences of random numbers, call Rnd with a negative argument immediately before using Randomize with a numeric argument.

See here for details.

The whole section:


Remarks

The Rnd function returns a value less than 1 but greater than or equal to zero.

The value of number determines how Rnd generates a random number:

For any given initial seed, the same number sequence is generated because each successive call to the Rnd function uses the previous number as a seed for the next number in the sequence.

Before calling Rnd, use the Randomize statement without an argument to initialize the random-number generator with a seed based on the system timer.

To produce random integers in a given range, use this formula:

Int((upperbound - lowerbound + 1) * Rnd + lowerbound)

Here, upperbound is the highest number in the range, and lowerbound is the lowest number in the range.

Note To repeat sequences of random numbers, call Rnd with a negative argument immediately before using Randomize with a numeric argument. Using Randomize with the same value for number does not repeat the previous sequence.


By way of example, if you put this code into Excel, it generates a different number each time you run it:

Sub xx()
    ' x = Rnd(-1) '
    Randomize 10
    MsgBox (Rnd)
End Sub

However, if you uncomment the x = Rnd(-1) line, it generates the same number on each run.

Note that you have to do two things. Call Rnd with a negative argument and call Randomize with a specific argument. Changing either of those things will give you a different seed (and therefore sequence).


Edit:

Re your comment:

By repeating sequence, I mean if you run a loop to get 10 random numbers, each random number in the list will be unique. In addition, if you were to run this sequence again, you would get the same 10 random numbers as before. Does what I'm describing make sense?

You now need one more piece of information. What you're asking for is not random numbers but a shuffling algorithm. I'll refer you to an earlier answer I gave on how to do this here. All you need to do is combine the shuffling algorithm with the seed-setting detailed above and you'll have your repeatable, unique sequence.


And here's some code that shows it in action. Every run of this subroutine returns the sequence 4 1 5 6 2 3 7 10 9 8 so I think that's what you were after, a repetable, "random", unique sequence. If you wanted to be able to generate different sequences (but still in a repeatable manner), you only need to change the value given to Randomize.

Option Explicit
Option Base 1

Sub xx()
    Dim x(10) As Integer
    Dim xc As Integer
    Dim xp As Integer
    Dim i As Integer
    Dim s As String

    For i = 1 To 10
        x(i) = i
    Next
    xc = 10

    i = Rnd(-1)
    Randomize 1

    s = "Values:"
    For i = 1 To 10
        xp = Int(Rnd * xc) + 1
        s = s & " " & CStr(x(xp))
        x(xp) = x(xc)
        xc = xc - 1
    Next i

    MsgBox (s)
End Sub
Community
  • 1
  • 1
paxdiablo
  • 772,407
  • 210
  • 1,477
  • 1,841
  • By repeating sequence, I mean if you run a loop to get 10 random numbers, each random number in the list will be unique. In addition, if you were to run this sequence again, you would get the same 10 random numbers as before. Does what I'm describing make sense? – sooprise May 21 '10 at 20:04
  • @Soo, that makes perfect sense unless I've misunderstood again :-) I've updated the answer with new information based on that comment. – paxdiablo May 21 '10 at 20:32
  • +1 Because I'm thankful I am able to adapt this to my needs despite how it works going way over my head. I can't tell what is going on after it adds `"Values:"` to `s`. Or, well, before that even, but that is the "number crunching" part which is the most important for understanding it. I wish I could see the "Evaluate Formula" equivalent step by step process for this/VBA in general. – ZealousHypocrites Dec 11 '15 at 21:18
  • @Corinne, it's known as a Fisher Yates shuffle and more detail on how it works can be found on the link given in the answer (http://stackoverflow.com/questions/1858610/different-numbers-from-1-to-10-using-vb6/1858800#1858800) or by searching for that term. The link goes through it step by step which shoould hopefully help. – paxdiablo Dec 11 '15 at 23:28
  • I had read that a bunch of times before my comment and it was still making my eyes cross, but I believe that is due to my deficiency in visualizing arrays. I'm not yet familiar with them enough to be able to "work" with them in "my" memory haha...however, it DID give me a good platform to stand on, and using that along with [this snazzy page](http://bost.ocks.org/mike/shuffle/) and I think I've got it now, thanks. :) [I know this is a bit "chatty" but I'm adding a link here too which supplements the answer so I hope chat happy mods leave this here...] – ZealousHypocrites Dec 14 '15 at 16:11
0

Actually there is no need to use Randomize to repeat Rnd pseudo-random sequence.

Take a look at the below line of code. It simply outputs 10 random numbers:

MsgBox Join(Array(Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd()), vbCrLf)

If you run it first time (i. e. with initial seed) or after resetting VBA code execution (reinitializing that way), then the output will be as follows:

0,7055475
0,533424
0,5795186
0,2895625
0,301948
0,7747401
1,401764E-02
0,7607236
0,81449
0,7090379

That sequence is returned in any VBA or VBS code for initial seed.

To repeat that sequence you just need to specify the seed by passing a negative number to Rnd function as argument:

MsgBox Join(Array(Rnd(-8716085), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd()), vbCrLf)

Or even so:

Rnd -16184694
MsgBox Join(Array(Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd(), Rnd()), vbCrLf)

The same with any other sequence, you need specify the seed as Rnd argument only.

omegastripes
  • 11,612
  • 3
  • 35
  • 77