【问题标题】:Fill array of random rumbers to sum in excel vba [closed]填充随机数数组以在excel vba中求和[关闭]
【发布时间】:2012-06-21 16:13:54
【问题描述】:

我正在尝试为其创建一个采样工具

我需要在 0 到 3000 之间以 500 的倍数随机生成数字,这样它们的总和就是一个固定数字,比如 12 个插槽中的 10000

除此之外,我需要运行大约 100000 到 1000000 的多次迭代(尚未决定。

我的方法是创建一个二维数组,设置一个约束来验证一次迭代的总和,并且只有当条件为真时才将其输入到最终的数据样本中。

我在以下代码中犯了一些非常可怕的错误,无法弄清楚在哪里......感谢帮助

Public Sub Generatenums()
    Dim GRP() As Long, Random() As Long
    Dim RandomTotal As Long, t As Long, w As Long, i As Long, j As Long

    ReDim GRP(1 To 100, 1 To 12)
    ReDim Random(1 To 12)

    For i = 1 To 100
        For j = 1 To 12
            Random(j) = Int(Rnd() * 7) * 500
            RandomTotal = RandomTotal + Random(j)
        Next j

        If RandomTotal = 10000 Then
            For k = 1 To 12
                GRP(i, k) = Random(k)
            Next k
        End If
    Next i

    Range("A1").Select
    For t = 1 To 100
        For w = 1 To 12
            Cells(t, w).Value = GRP(t, w)
        Next w
    Next t
End Sub

【问题讨论】:

  • 首先,你应该用嵌套的 for 循环重写它,而不是硬编码 1、2、3... 12。
  • 我可以尝试将变量 j 从 1 变为 12。我同意它使程序不那么笨重
  • 总体上它还使其更具可读性,这可能有助于您(或其他人)更轻松地诊断问题。另外,RandomTotal 目前的用途是什么?
  • 好吧,这样更好。但是,目前,如果您的总和不正确,您只需转到 i 的下一个值,而无需向该 GRP 行填充值。你有几个选择。您可以在第一个循环中循环以继续生成数字,直到总和为 10000。或者您可以尝试提出一种算法来保证您的数字之和为 10000。(我必须警告您,12 个数字总和为 10000给每个数字的平均值约为 833,但随机生成 0 到 3000 之间的数字会给你平均每个 1500 的数字,几乎是你想要的两倍!)
  • 随机化 11 个值,然后从 10,000 中减去它们的总数,得到第 12 个。如果最后一个不在您的范围内,您将不得不重新开始,但它会比生成所有 12 个更快地产生结果。

标签: arrays excel vba random sampling


【解决方案1】:

Fantom,欢迎来到 SO。

评论者是对的:这将需要很长时间才能运行。

不要将其视为要填充为某个总和的数组,而应将其视为弹球盘或Galton Board,其中有 20 个球在周围弹跳并最终进入底部的垃圾箱。为什么是20?因为您想要以 500 为增量的 10000 的总和,并将 10000/500 = 20 视为一个球。

现在程序可以在线性时间内运行。您不会随机化总和,而是随机化球将落入 12 个插槽中的哪个插槽。然后将每个插槽中的球数乘以 500,总和将始终为 10000。

其中一个循环如下所示:

For i = 1 To 20
  x = Rnd() * 12 + 1
  If x > 12 Then x = 12
  If x < 1 Then x = 1
  bin(x) = bin(x) + 1
Next i

这足以解决您的问题,还是您需要更多?

【讨论】:

  • 在x = Rnd() * 12 + 1的计算中,运行100次,第12个bin总是最大的,第一个bin总是最小的。如果去掉 +1,第 12 个 bin 总是最小的,第一个 bin 总是最大的。使用 0.5 似乎可以解决问题。
  • 感谢 rajah,您建议的方法确实令人耳目一新,根据您的说法,将 bin 大小限制为 6 的最佳方法是,因为单个 bin 中的总值不应超过 3000
  • 同样通过数组求解似乎可以减少 100K 迭代所花费的时间,几乎不需要 3 分钟。
  • 运行速度更快是有道理的。这就是我所说的“线性时间”。至于限制为 6,我认为您可以将上面的循环从 for 循环更改为 do while。让它从 1 开始计数,并在每次填满一个 bin 时递增。在填充之前检查 bin(x),如果它是 6 或更大,则跳过循环而不增加。
  • 非常感谢 Rajah,它已经在工作了,如果没有您的帮助,我无法做到。我也会上传实际代码供大家参考。
猜你喜欢
  • 1970-01-01
  • 2017-06-04
  • 2020-07-16
  • 1970-01-01
  • 1970-01-01
  • 2011-01-23
  • 1970-01-01
相关资源
最近更新 更多