This code is supposed to generate a sequence of 10,000 random numbers in VBA. For some reason I am only able to produce a unique sequence of length 5842, and then it repeats. But, and this is the strangest part, each time I run the code, the sequence starts in a different place. For example in one run, the elements following element 2660 are the same as those following element 8502 (8502-2660= 5842). The next run, I get a sequence that repeats following elements 3704 and 9546 (9546-3704=5842). And so on.
Function NormRand() As Double
' NormRand returns a randomly distributed drawing from a
' standard normal distribution i.e. one with:
' Average = 0 and Standard Deviation = 1.0
Dim fac As Double, rsq As Double, v1 As Double, v2 As Double
Static flag As Boolean, gset As Double
' Each pass through the calculation of the routine produces
' two normally-distributed deviates, so we only need to do
' the calculations every other call. So we set the flag
' variable (to true) if gset contains a spare NormRand value.
If flag Then
NormRand = gset
' Force calculation next time.
flag = False
Else
' Don't have anything saved so need to find a pair of values
' First generate a co-ordinate pair within the unit circle:
Do
v1 = 2 * Rnd - 1#
v2 = 2 * Rnd - 1#
rsq = v1 * v1 + v2 * v2
Loop Until rsq <= 1#
' Do the Math:
fac = Sqr(-2# * Log(rsq) / rsq)
' Return one of the values and save the other (gset) for next time:
NormRand = v2 * fac
gset = v1 * fac
flag = True
End If
End Function
For some reason I am only able to produce a unique sequence of length 5842, and then it repeats. But, and this is the strangest part, each time I run the code, the sequence starts in a different place
That's by design and well known - that's why the number generation is labelled pseudo random and not random.
By the way, I notice that you are multiplying the two values. That may not be a good idea - as mentioned here.
In your function, you may try to replace Rnd
with RndDbl
:
Public Function RndDbl(Optional ByRef Number As Single) As Double
' Exponent to shift the significant digits of a single to
' the least significant digits of a double.
Const Exponent As Long = 7
Dim Value As Double
' Generate two values like:
' 0.1851513
' 0.000000072890967130661
' and add these.
Value = CDbl(Rnd(Number)) + CDbl(Rnd(Number) * 10 ^ -Exponent)
RndDbl = Value
End Function
and then modify your code to include a dynamic seed by calling Timer
:
Do
v1 = 2 * RndDbl(-Timer) - 1#
v2 = 2 * RndDbl(-Timer) - 1#
rsq = v1 + v2
Loop Until rsq <= 1#
The generated values will still not be true random, but should not take form of a repeated sequence.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With