首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何理解过多播种RNG所引起的自相关?

如何理解过多播种RNG所引起的自相关?
EN

Stack Overflow用户
提问于 2016-12-12 13:51:45
回答 2查看 248关注 0票数 6

作为对这个问题的响应,我运行了以下VBA实验:

代码语言:javascript
运行
复制
Sub Test()
    Dim i As Long, A As Variant
    Dim count1 As Long, count2 As Long
    ReDim A(1 To 10000)

    For i = 1 To 10000
        Randomize
        A(i) = IIf(Rnd() < 0.5, 0, 1)
    Next i
    
    'count how often A(i) = A(i+1)
    For i = 1 To 9999
        If A(i) = A(i + 1) Then count1 = count1 + 1
    Next i
    
    For i = 1 To 10000
        A(i) = IIf(Rnd() < 0.5, 0, 1)
    Next i
    
    'count how often A(i) = A(i+1)
    For i = 1 To 9999
        If A(i) = A(i + 1) Then count2 = count2 + 1
    Next i

   Debug.Print "First Loop: " & count1
   Debug.Print "Second Loop: " & count2 & vbCrLf
   
End Sub

当我看到这样的输出时:

代码语言:javascript
运行
复制
First Loop: 5550
Second Loop: 4976

我非常肯定我知道发生了什么: VBA正在将系统时钟转换成更低分辨率(也许是微秒)的东西,这将导致Randomize有时在两次或更多次通过循环时产生相同的种子。在我最初的回答中,我甚至自信地断言了这一点。但是,我运行了更多的代码,并注意到输出有时是这样的:

代码语言:javascript
运行
复制
First Loop: 4449
Second Loop: 5042

过度播种仍然导致明显的自相关--但方向相反(而且出乎意料)。具有相同种子的连续通过循环应该产生相同的输出,因此我们应该看到连续值的一致性比机会预测的要多,而不是比机会预测的更多。

出于好奇,我将代码修改为:

代码语言:javascript
运行
复制
Sub Test2()
    Dim i As Long, A As Variant
    Dim count1 As Long, count2 As Long
    ReDim A(1 To 10000)

    For i = 1 To 10000
        Randomize
        A(i) = Rnd()
    Next i
    
    'count how often A(i) = A(i+1)
    For i = 1 To 9999
        If A(i) = A(i + 1) Then count1 = count1 + 1
    Next i
    
    For i = 1 To 10000
        A(i) = Rnd()
    Next i
    
    'count how often A(i) = A(i+1)
    For i = 1 To 9999
        If A(i) = A(i + 1) Then count2 = count2 + 1
    Next i

   Debug.Print "First Loop: " & count1
   Debug.Print "Second Loop: " & count2 & vbCrLf
   
End Sub

它总是提供以下输出:

代码语言:javascript
运行
复制
First Loop: 0
Second Loop: 0

似乎并不是这样的,对Randomize的连续调用有时会返回相同的种子(至少不够频繁地产生影响)。

但如果这不是自相关的来源--什么是?为什么它有时表现为消极的而不是正的自相关?

EN

Stack Overflow用户

发布于 2016-12-13 17:27:26

Randomize方法以当前系统时间作为种子初始化Rnd函数,还可以指定一个带有Randomize的数字作为种子。

我决定在重复自己之前测试一个序列持续多长时间:

代码语言:javascript
运行
复制
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

该子序列生成数字0- 9的随机序列,当序列变为偶数长度时,将测试该序列的前半部分是否与下半部分匹配,如果符合,则输出重复之前达到的序列长度。在运行了几次之后,在开始时对一个数字重复两次的贴现,结果是256 (很好)。

Randomize提供任何值仍将返回256个结果。

我们随机化了Rnd 每一个循环,那么这里发生了什么呢?

正如我在一开始所说的,如果Randomize没有值,它将使用系统时间作为种子。这个时候的解决方案,我似乎找不到来源,但我相信它是低的。

我使用timer的值进行了测试,它将一天中的时间以秒为单位返回到小数点后的2位(例如60287.81)。我还尝试了GetTickCount,它以毫秒为单位返回系统活动时间(启动时开始计数)。这两种方法都会导致256序列的限制。

那么,为什么当我们将每一个循环随机化时,序列会重复呢?实际上,代码是在毫秒内执行的。本质上,我们提供了相同的数字来随机化每一个循环,所以我们实际上并没有对种子进行洗牌。

因此,在没有Rnd Randomize**?**的情况下,更具有随机性吗?

在没有Randomize的情况下,我再次运行了上面的潜艇;没有返回任何内容。我把循环计数提高到2,000,000,还是什么也没有。

我设法通过工作簿算法来源 Rand公式,我认为它与没有初始化种子的Rnd相同:

在第一项输入前,应将C、IY、IZ设置为1至30000之间的整数值。 九=国防部(171* IX,30269) IY =国防部(172* IY,30307) IZ =国防部(170* IZ,30323) 随机=AMOD(浮点数(IX)/ 30269.0 +浮点数(IY)/ 30307.0 +浮点数(IZ)/ 30323.0,1.0)

它是一个迭代函数,它使用上一次调用的结果生成一个新的数字。作为Wichman过程的引用,它保证在序列重复之前会生成10^13个以上的数字。

Rnd 解决问题

要使算法工作,首先需要使用IXIYIZ的值初始化它。这里的问题是,我们不能用随机变量初始化算法,因为我们需要这个算法来获得随机值,所以唯一的选择是提供一些静态值来使其正常运行。

我对此进行了测试,情况似乎是这样的。打开一个新的Excel实例,? Rnd()返回0.70554。再次执行相同的操作将返回完全相同的数字。

因此,我们遇到的问题是,没有使用Rnd的情况下,Randomize会给我们一个更长的随机数序列,但是每次打开Randomize时,这个序列都会从相同的位置开始。如果函数依赖于随机生成(如密码生成),这是不够的,因为每次打开Excel时,我们都会得到相同的重复结果。

解决方案

下面是我想出的一个函数,它似乎运行得很好:

代码语言:javascript
运行
复制
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

它利用GetTickCount函数作为Randomize种子。每个调用在一个randomCount变量中添加一个,在每255个运行之后,宏被迫睡眠1毫秒(尽管在我的系统中这实际上是15毫秒),这样GetTickCount的种子就会改变,因此Rnd将返回一个新的数字序列。

这当然会返回相同的序列,如果偶然在相同的系统时间使用,但在大多数情况下,它将是一个充分的方法,以产生更多的随机数。如果不是,它将需要一些花哨的工作,使用类似的Random.Org API

票数 1
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41102399

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档