Excel VBA的有趣行为随机数例程

时间:2012-06-17 18:23:43

标签: vba random excel-vba excel

我试图通过以下算法通过vba生成一堆随机排列:

Function RandNumber(Bottom As Integer, Top As Integer, _
                Amount As Integer) As Integer()

Dim iArr As Variant
Dim i As Integer
Dim r As Integer
Dim temp As Integer
Dim bridge() As Integer

'Application.Volatile

ReDim iArr(Bottom To Top)

For i = Bottom To Top
    iArr(i) = i
Next i
Randomize
For i = Top To Bottom + 1 Step -1
    r = Int(Rnd() * (i - Bottom + 1)) + Bottom
    temp = iArr(r)
    iArr(r) = iArr(i)
    iArr(i) = temp
Next i

ReDim Preserve bridge(1 To Amount)
For i = Bottom To Bottom + Amount - 1
    bridge(i - Bottom + 1) = iArr(i)
Next i

RandNumber = bridge

End Function

RandNumber基本上做的是它根据用户提供的底部和顶部值随机给出排列。示例RandNumber(1,2,1)将随机为12

现在我通过以下例程测试此功能

Sub RandNos()
Dim z() As Variant
ReDim Preserve z(1 To 2560)
For i = 1 To 2560
z(i) = RandNumber(1, 2, 1)
Next i
For i = 1 To 2560
ThisWorkbook.Sheets("Sheet2").Range("A1").Offset(i - 1, 0) = z(i)
Next i
End Sub

令我惊讶的是,“随机”数字在256次运行后正好重复! (好吧,上面i的值2560并不完全是同时发生的。我怀疑大约256行有一些模式,因此将i作为2560)

此外,当我用略微修改的子程序测试上述函数时:

Sub RandNos2()
For i = 1 To 2560
ActiveSheet.Range("A1").Offset((i - 1) Mod 256 + 1, Int((i - 1) / 256)) = RandNumber(1, 2, 1)
Next i
End Sub

模式消失了。 (至少在256个值之后重复的模式消失。不确定是否出现另一个模式。)

现在根据我的知识,Randomize应该通过生成适当的种子来控制随机性,而vba中的Randomizetimer获取种子。所以我的假设是,在第一个RandNos()子例程中,更新发生得如此之快,以至于种子的更新速度不够快。当我使用第二个子例程测试模式时,模式就消失了,因为在第二个例程中,excel需要更长的时间来在工作表中编写代码,因此给代码一些机会更新timer并使用种子随机数 - 支持我的假设。

所以我的问题是

  1. 我的假设是否正确。
  2. 我是否还希望在Excel VBA中生成“随机”模式。
  3. 我错误地使用Randomize此处
  4. 提前感谢您就此问题提出建议。

    编辑:评论中的一条建议是我们只应拨打Randomize一次。我试过这样做,似乎工作。但是,我仍然想知道上面使用Randomize出了什么问题。

3 个答案:

答案 0 :(得分:3)

您应该只拨打Randomize一次。如果多次调用RandNos(),请在调用Randomize的方法中使用RandNos()

答案 1 :(得分:3)

在回答您的编辑时,您的假设是正确的。

Randomize花费时间并生成种子。种子只是Rnd的起点。

但是,请注意,Randomize不是一对一的,这意味着对于Randomize(即时间)的任何给定输入,它不会每次都生成相同的种子。您似乎已经发现Randomize对于每个给定的输入都有256个种子的序列。因此,你得到一个256个数字的重复序列,它们应该是随机的,但显然不是。

参考:Randomize和CS类的VBA帮助页面

答案 2 :(得分:0)

只是为了将来引用遇到此问题的任何人,我决定尝试“减慢”子程序,以便让系统计时器重置。 Application.wait效果不佳,但我发现通过在debug.print调用之上添加一条简单的randomize行,它会将执行速度降低到足以让它不会每256次重复一次。不会显着增加子程序的总运行时间。对于那些不介意牺牲一点优化以便对伪随机性进行非常简单的修复的人来说,这只是一个想法。