为什么我的随机数在 Excel 中没有相应变化?

Why are my random numbers not changing accordingly in Excel?

我下面有一些代码可以在 Excel 中生成一些随机数:

Sub Macro1()

Dim RA1 As Variant
ReDim RA1(1 To 5)

For i = 1 To 5

    Rnd (-1)
    Randomize i

    For j = 1 To 5
            
        RA1(j) = Rnd
                             
    Next j
    
    With Sheets("Sheet1")
    
        .Range(Cells(i, 1), Cells(i, 5)).Value = RA1
        
    End With
    
Next i

End Sub

这段代码基本上生成了 5 行 5 个随机数,但它并不是 运行 应有的样子。当我在我的 iMac(2021)上 运行 这段代码时,每行中的随机数完全相同。但是,这段代码应该生成 5 行不同的随机数。

这里是事情变得更加奇怪的地方。当我在我的 Windows 笔记本电脑上 运行 这段代码时,输​​出是我想要的——也就是说,我确实得到了 5 行不同的随机数。我已经和我的教授谈过这个,他也在他的 Windows 电脑上试过了,得到了 5 行不同的随机数。

总而言之,我们基本上不知道为什么我的 iMac 无法 运行 这段代码。有没有人猜测为什么这里存在这种差异?例如,我的 iMac Excel 中是否有任何设置阻止我的代码正确 运行ning?

任何解释和解决方案将不胜感激! :)

如果您阅读 Randomize statement 的手册,您可以找到以下内容:

To repeat sequences of random numbers, call Rnd with a negative argument immediately before using Randomize with a numeric argument. Using Randomize with the same value for number does not repeat the previous sequence.

所以我强烈建议删除 Rnd (-1),这会使它重复随机数序列。

也尝试从 Randomize i 中删除种子并仅使用 Randomize 以便计算机将系统计时器作为种子(以获得更好的随机数)。


// 根据评论编辑

如果您每次都需要相同的数字但每次都需要不同的数字rows/columns那么您可能需要在第一次循环之前进行初始化。

Rnd -1
Randomize 1 'if you don't need the same seed everytime use Randomize without number

For i = 1 To 5

您描述的行为是一个错误。

首先,如果我们替换行:

Randomize i

与:

Randomize 0

我们可以看到在 Windows 上得到的重复值与在 Mac 上得到的重复值完全相同:

这立即让我想到只有两种可能的解释:

  1. 可能是算法不同
  2. 出现问题,i 的值不正确 passed/read。

为了找规律,我用了单独的方法(暴力破解i/x),找到了下面的幻数。同样,如果我们替换行:

Randomize i

与:

#If Mac Then
    Dim arr() As Variant: arr = Array(26489, 63707, 185603, 15365, 92513)
    Randomize i / arr(i - 1)
#Else
    Randomize i
#End If

我们在 Windows 和 Mac 上得到相同的结果。

我在那些幻数中找不到明确的模式,所以我放弃了算法不同。这让我找到了 issue/bug.

经过反复试验,我发现如果我们将 Double 数据类型传递给 Randomize 方法,它不会读取完整的 8 个字节,而只会读取前 4 个字节。这就是除以那些神奇数字的原因,因为(这些除法的)结果数字使用前 4 个字节(包括指数位)而不是 8 个完整字节。

解决方法是将双精度值(向左)偏移 4 个字节。这是适用于 Windows 和 Mac 的最终代码:

Option Explicit

#If Mac Then
    #If VBA7 Then
        Public Declare PtrSafe Function CopyMemory Lib "/usr/lib/libc.dylib" Alias "memmove" (Destination As Any, Source As Any, ByVal Length As LongPtr) As LongPtr
    #Else
        Public Declare Function CopyMemory Lib "/usr/lib/libc.dylib" Alias "memmove" (Destination As Any, Source As Any, ByVal Length As Long) As Long
    #End If
#End If

Sub Macro1()
    Dim i As Long
    Dim j As Long
    Dim RA1 As Variant
    ReDim RA1(1 To 5)
    
    For i = 1 To 5
        Rnd (-1)
        
        #If Mac Then
            Dim d As Double
            
            d = CDbl(i)
            CopyMemory d, ByVal VarPtr(d) + 4, 4 'Read the last 4 double bytes into the first 4
            Randomize d
        #Else
            Randomize i
        #End If

        For j = 1 To 5
            RA1(j) = Rnd
        Next j
        
        With Sheets("Sheet1")
            .Range(Cells(i, 1), Cells(i, 5)).Value = RA1
        End With
    Next i
End Sub

您会注意到我还添加了 Option Explicit、声明了所有变量并缩进了代码。