This article assumes you already know how to use Randomize() and Rnd() to generate a sequence of pseudo random numbers. If you don't know please read How can I use Random numbers? [Tutorial].

MSDN tells us that in order to vary the sequence of numbers returned by Rnd we should call Randomize to reseed it. Technically Rnd has only one sequence, Randomize works by shifting the starting point. What MSDN does not tell us is that the shift that Randomize performs is limited to small portion of the full sequence of Rnd, 1/256 to be exact.

In terms of other pseudo random number generators Rnd uses a fairly weak algorithm. The full sequence consists of exactly 16777216 (&h1000000) different numbers (every number being multiple of 1/16777216), divide that by 256 and we are only left with 65536 different entry points. This might well be okay for most applications but it would be nice from time to time to have the option of more than this.

The solution is really quite simple. MSDN tells us that if we call Rnd with a negative argument then that argument itself is used as the seed. It turns out that seeding like this gives full access to the sequence, all we need to do is supply a suitable volatile number. The two most obvious choices are the returns of Timer() and Now(). Using Rnd -Timer although better than Randomize alone still does not quite allow for all possible entry points. Now() on the other hand allows access to pretty much the whole sequence but as the process casts to a single the least significant bits are chopped off leaving a number which remains static for long periods. Multiply them together and we get a good seed.

Code:
Private Sub Form_Load()
  Rnd -Timer * Now
  Randomize
End Sub
That's all there is to it, Rnd is now properly randomised (or randomized if you prefer )

For a better PRNG with a much larger sequence check out the Wichmann-Hill Pseudo Random Number Generator over in the code bank.

For an under the hood explanation on Rnd and Randomize see this external article on the subject