Для довольно полного ответа:
Существует множество способов генерации случайных чисел, но одним из них является использование API Windows для выполнения тяжелой работы. Windows имеет функции API для генерации криптографически безопасных случайных байтов, и эти функции могут использовать аппаратные поставщики случайных чисел.
Сначала мы объявляем функции API:
Public Declare PtrSafe Function BCryptOpenAlgorithmProvider Lib "bcrypt.dll" (ByRef phAlgorithm As LongPtr, ByVal pszAlgId As LongPtr, ByVal pszImplementation As LongPtr, ByVal dwFlags As Long) As Long
Public Declare PtrSafe Function BCryptGenRandom Lib "bcrypt.dll" (ByVal hAlgorithm As LongPtr, pbBuffer As Any, ByVal cbBuffer As Long, ByVal dwFlags As Long) As Long
Public Declare PtrSafe Function BCryptCloseAlgorithmProvider Lib "bcrypt.dll" (ByVal hAlgorithm As LongPtr, ByVal dwFlags As Long)
Затем, мы используем этот вызов и используем модуль для уменьшения нашего числа до единицы в желаемом диапазоне:
Public Function RandomRangeWinApi(Lower As Long, Upper As Long) As Long
Dim hAlg As LongPtr
Dim iAlg As String
iAlg = "RNG" & vbNullChar
BCryptOpenAlgorithmProvider hAlg, StrPtr(iAlg), 0, 0
Dim lRandom As Long
BCryptGenRandom hAlg, lRandom, LenB(lRandom), 0
RandomRangeWinApi = Abs(lRandom) Mod (Upper - Lower + 1) + Lower
BCryptCloseAlgorithmProvider hAlg, 0
End Function
Этот подход хорош, если вы предполагаете, что целое число имеет бесконечный диапазон значений. Тем не менее, это не так, что означает, что на пределе это неточно. Точно так же умножение предполагает бесконечно точное число, которое также не соответствует действительности и вызывает небольшое смещение.
Мы можем обойти это, непосредственно используя двоичное представление чисел и отбрасывая числа, которые выходят за пределы этого шаблона :
Public Function RandomRangeExact(Lower As Long, Upper As Long) As Long
'Initialize random number generator
Dim hAlg As LongPtr
Dim iAlg As String
iAlg = "RNG" & vbNullChar
BCryptOpenAlgorithmProvider hAlg, StrPtr(iAlg), 0, 0
'Initialize bit template
Dim template As Long
Dim i As Long
Do While template < Upper - Lower
template = template + 2# ^ i
i = i + 1
Loop
Dim lRandom As Long
Do
'Generate random number
BCryptGenRandom hAlg, lRandom, LenB(lRandom), 0
'Limit it to template
lRandom = lRandom And template
Loop While lRandom > (Upper - Lower) 'Regenerate if larger than desired range (should happen less than 50% of times)
RandomRangeExact = lRandom + Lower
BCryptCloseAlgorithmProvider hAlg, 0
End Function
Теперь давайте исследуем производительность вашего решения и обе возможности для игры в кости: я симулировал 100000 случайных чисел для каждого подхода от 1 до 6.
Это результат:
Хотя первый подход, по-видимому, имеет большую дисперсию между числами (особенно меньше единиц и больше двойок), для большинства приложений я бы предположил первое достаточно точно.