【问题标题】:Finding a good replacement for Rnd in Excel VBA在 Excel VBA 中寻找 Rnd 的良好替代品
【发布时间】:2020-12-21 06:34:55
【问题描述】:

众所周知,Excel 中的 Rnd 函数很弱,而 Excel 中的 RAND 函数基于 Mersenne 算法,并且要强大得多。我一直在尝试寻找一种快速且强大的 Rnd 替代方案,并查看了各种选项,包括使用 Mersenne,但这需要大量代码。

【问题讨论】:

标签: excel vba random numbers


【解决方案1】:

另一种选择是从 VBA 调用 Excel RAND 函数,但是一次调用一个会非常慢。但是,Excel365 中的新函数 RANDARRAY 允许 VBA 一次性从 Excel 中调用大量随机数,根据需要使用它们,并在需要时返回更多。这种方法速度快(仅比 Rnd 慢 4 倍,比 Mersenne 代码快)且紧凑 - 代码如下。

我分享这个是希望找到解决这个问题的最佳集体解决方案。

Function RandXL() As Single
  Static Remaining As Long, R() As Variant
  If Remaining = 0 Then 'get more numbers if necessary
    R = Application.WorksheetFunction.RandArray(1000, 1)
    Remaining = 1000
  End If
  RandXL = R(Remaining, 1)
  Remaining = Remaining - 1
End Function

【讨论】:

    【解决方案2】:

    您可以使用真正的随机数 - 如我的项目 VBA.Random 所示。

    它包含 Rnd 的直接替换:

    ' Returns a true random number as a Double, like Rnd returns a Single.
    ' The value will be less than 1 but greater than or equal to zero.
    '
    ' Usage: Excactly like Rnd:
    '
    '   TrueRandomValue = RndQrn[(Number)]
    '
    '   Number < 0  ->  The same number every time, using Number as the seed.
    '   Number > 0  ->  The next number in the pseudo-random sequence.
    '   Number = 0  ->  The most recently generated number.
    '   No Number   ->  The next number in the pseudo-random sequence.
    '
    ' 2019-12-21. Gustav Brock, Cactus Data ApS, CPH.
    '
    Public Function RndQrn( _
        Optional ByVal Number As Single = 1) _
        As Double
        
        Static Value            As Double
        
        Select Case Number
            Case Is > 0 Or (Number = 0 And Value = 0)
                ' Return the next number in the random sequence.
                Value = CDbl(QrnDecimal)
            Case Is = 0
                ' Return the most recently generated number.
            Case Is < 0
                ' Not supported by QRN.
                ' Retrieve value from RndDbl.
                Value = RndDbl(Number)
        End Select
        
        ' Return a value like:
        ' 0.171394365283966
        RndQrn = Value
        
    End Function
    

    此外,还包含一个演示 (RandomQrn.xlsm) 可供下载。

    这设置了对 Microsoft Access 16.0 对象库 的引用,其中使用了 Nz 函数。如果您不想拥有此参考,则此替代品可以:

    ' Replacement for the function Application.Nz() of Access.
    '
    ' 2015-12-10. Gustav Brock, Cactus Data ApS, CPH.
    '
    Public Function Nz( _
        ByRef Value As Variant, _
        Optional ByRef ValueIfNull As Variant = "") _
        As Variant
    
        Dim ValueNz     As Variant
        
        If Not IsEmpty(Value) Then
            If IsNull(Value) Then
                ValueNz = ValueIfNull
            Else
                ValueNz = Value
            End If
        End If
            
        Nz = ValueNz
        
    End Function
    

    【讨论】:

    • 谢谢,古斯塔夫。它似乎做一个网络查询来检索随机数。我看不出这会很快,如果您没有互联网连接,或者您的网站已关闭,您会怎么做?它与所有随机性测试套件(例如 Diehard)的配合情况如何?
    • 这取决于您如何称重“快”和“强”以及您如何衡量 - 我们不知道。请注意,您可以将一批数字作为数组检索,这是您在 VBA 中可以拥有的最快的集合。至于随机性,请研究我在文档中提供链接的来源。如果你不能依赖互联网连接——这几天看起来很奇怪——去 Quantis 购买附加 PCI 卡;这也将提供终极速度(有代价)。
    • 两件事 1. 代码在看到 Nz undefined 时抛出错误 2. 您的文档没有使用任何标准测试套件测试该方法
    • 演示设置了对访问的引用以达到 Nz - 请参阅编辑后的答案。另外,请理解,我的项目的目标不是证明源代码的随机性(我没有理由怀疑),而是展示如何在 VBA,特别是 Access 和 Excel 中轻松利用这个伟大的源代码。如果您碰巧运行了这些测试中的任何一个,我很乐意将结果包含在文档中。
    • 这是个好主意,不是我想要的,但其他人可能需要非常高质量的随机性。我建议运行一些正式的随机性测试,以确保它像您认为的那样随机,并且实现中没有错误。
    猜你喜欢
    • 1970-01-01
    • 2017-01-01
    • 1970-01-01
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多