The Randomize method initializes the Rnd function with the current system time as it is seed, you can also specify a number with Randomize that will be used as a seed.
I decided to check how long the sequence lasts until it repeats:
Sub randomRepeatTest() For i = 1 To 100000 Randomize randomThread = randomThread & Int(9 * Rnd + 1) If i Mod 2 = 0 Then If Left(randomThread, i / 2) = Right(randomThread, i / 2) Then Debug.Print i / 2 Exit Sub End If End If Next i End Sub
This subgenerator generates a random sequence of digits 0-9, and as the sequence becomes even, it is checked to see if the first half of the sequence matches the second half, and if so, it displays the length of the sequence before repeating. After starting it several times and at a discount, when the number is repeated twice at the beginning, the result is 256 (good).
Providing any value to Randomize will still return a result of 256.
We randomize Rnd every cycle, so what happens here?
Well, as I said at the beginning, if the Randomize value is not specified, it will use the system time as a seed. The resolution of this time is something that I seem to be unable to find, but I find it low.
I tested using a timer value that returns the time of day in seconds up to 2 decimal places (e.g. 60287.81). I also tried GetTickCount , which returns the system active time (starts counting at boot) in milliseconds. Both of them still lead to a 256 limit sequence.
So why, when we randomize each cycle, does the sequence repeat? Well, actually, the code is executed within a millisecond. Essentially, we provide the same number to randomize each cycle, and therefore we do not actually shuffle the seed.
So is Rnd more random without randomize?
I ran the above subgroup again without Randomize ; nothing came back. I increased the number of cycles to 2,000,000; nothing yet.
I managed to fix the algorithm used according to the formula of the book Rand , which, in my opinion, is the same as Rnd without initialized seed:
C IX, IY, IZ SHOULD BE INSTALLED FOR INTEGRATION BETWEEN 1 AND 30,000 BEFORE THE FIRST ENTRANCE
IX = MOD (171 * IX, 30269)
IY = MOD (172 * IY, 30307)
IZ = MOD (170 * IZ, 30323)
RANDOM = AMOD (FLOAT (IX) /30269.0 + FLOAT (IY) /30307.0 + FLOAT (IZ) /30323.0, 1.0)
This is an iterative function that uses the result of a previous call to generate a new number. The indicated Wichmann-Hill procedure ensures that more than 10 ^ 13 numbers will be generated before the sequence repeats.
Problem with Rnd
For the algorithm to work, you must first initialize it with the values for IX , IY and IZ . The problem that we have here is that we cannot initialize an algorithm with random variables, since we need this algorithm to obtain random values, so the only option is to provide some static values to get it.
I tested this and it seems to be so. Opening a new instance of Excel ? Rnd() ? Rnd() returns 0.70554. Executing the same result returns the same number.
Thus, the problem we have, Rnd without using Randomize , gives us a much longer sequence of random numbers, however this sequence starts in the same place every time you open Excel. If the functions depend on random generation, for example, password generation, this is not enough, since we will get the same duplicate results every time you open Excel.
Decision
Here is a function that I came up with and seems to work well:
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal Milliseconds As LongPtr) Public Declare Function GetTickCount Lib "kernel32" () As Long Public randomCount As Long Function getRandom() If randomCount Mod 255 = 0 Then Sleep 1 End If Randomize GetTickCount getRandom = Rnd() randomCount = randomCount + 1 End Function
The GetTickCount function is GetTickCount . Each call adds 1 to the randomCount variable, and after every 255 starts, the macro is forced to sleep for 1 millisecond (although it actually works for about 15 on my system), so the GetTickCount seed will be changed and therefore a new sequence of numbers will be returned to Rnd
This, of course, will return the same sequence if it is accidentally used in the same system time, but in most cases it will be a sufficient way to generate more random numbers. If this is not the case, some fancy work will be needed using something like the Random.Org API .