-
Oct 27th, 2010, 05:32 PM
#1
Squeezing the most out of Randomize and Rnd [vb6 and earlier]
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
-
Jul 29th, 2015, 02:59 PM
#2
New Member
Re: Squeezing the most out of Randomize and Rnd [vb6 and earlier]
Originally Posted by Milk
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.
I've been trying to test this assertion but I can't seem to verify it. I wrote the following program to test it.
Code:
Const STEPS As Long = 100000000 ' 100 million iterations
Const SIZE As Long = &H1000000 ' Numbers in sequence
ReDim a(SIZE) As Boolean
Dim i As Long, r As Single, j As Long, c As Long
For i = 1 To STEPS
' Reseed on each iteration to get a new entry point...
Randomize
' Get the random number at this entry point...
r = Rnd()
' Convert from Single to Long...
j = r * SIZE
' Flag it in our array as being visited and increment our unique entry-point count...
If Not a(j) Then
a(j) = True
c = c + 1
End If
Next
MsgBox "Unique entry points: " & c
This returns over 300,000 entry points. Not nearly 16+ million but also not 65,536.
Is there something flawed with this test?
Last edited by BondDotCom; Jul 30th, 2015 at 10:11 AM.
Reason: Clearer example
-
Dec 30th, 2015, 08:00 AM
#3
Re: Squeezing the most out of Randomize and Rnd [vb6 and earlier]
Hi, you might have moved on now but I've just noticed your question. I'm not so active these days.
The test is flawed I'm afraid in that each time you call Rnd you shift the sequence by 1 so the call to Randomize is reseeding from that new position and not the original. To prove the assertion you need to reset the internal state which can be achieved by calling Rnd with a fixed negative argument just before you call Randomize. The idea is to simulate the effect of a single call to Randomize on program start up which is how we are often encouraged to use it. Not sure but if I remember correctly the test needs to be run for a long time (24 hours). You might also find it interesting to count rather than just set booleans, that way you can see exactly how many times each number is visited.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|