【问题标题】:How does VBA rand generate random numbers using the upperbound and lowerbound?VBA rand 如何使用上限和下限生成随机数?
【发布时间】:2016-07-12 17:11:23
【问题描述】:

所以也许这是多余的,也许这就像问为什么大多数人天生就有 5 个手指,最后的简短回答总是:因为它就是这样,它只是工作,但我讨厌这个答案,该死我想要了解 VBA 中的 Rnd() 函数是如何工作的。

Ms Office Excel 的 MSDN 说 RND 定义为:

Rnd[(number)] 'The optional number argument is a Single or any valid numeric expression.

继续说

"number的值决定了Rnd如何生成随机数:对于 任何给定的初始种子,都会生成相同的数列,因为 对 Rnd 函数的每次连续调用都使用前一个数字作为 序列中下一个数字的种子。”

接下来是:

要生成给定范围内的随机整数,请使用以下公式:

Int((upperbound - lowerbound + 1) * Rnd + lowerbound)

例如:
Dim MyValue MyValue = Int((6 * Rnd) + 1) ' Generate random value between 1 and 6.

但它是如何工作的?这些数字是从哪里来的?为什么6 * Rnd + 1 会得到一个介于 1 和 6 之间的随机数,而 6 * Rnd + 5 会得到一个介于 5 和 10 之间的数字?

此外,如果 VBA 的创建者很清楚使用什么公式可以成功地将其缩小到特定范围,为什么不让 RND 函数带有可选的 Ubound 和 Lbound 参数?我不可能是唯一一个研究这个公式的人,这到底是什么?

归根结底,它当然可以满足我的任何伪随机数需求,也许我正在寻找一匹礼物马,但仍然如此!


编辑


我突然想到这个问题可能基于数学本身。如果你取一个小整数,你会应用什么函数来使该整数适合指定范围..那么任何人都可以解释这个公式是如何工作的吗?

【问题讨论】:

  • 给出的原始公式中的常数“+1”需要为 0.5(0.499999 重复,但 w/e) 怎么还没人提到这个呢?还是证明我错了?使用 +1 可能会导致您超出上限。

标签: vba excel random


【解决方案1】:

这是一个分步指南:

  1. Rnd 给出 0 到 之间的随机小数
  2. 6 * Rnd 给出 0 到 之间的随机小数
  3. Int(6 * Rnd) 将其舍入 向下,因此您会得到一个介于 0 和 5 之间的随机值

在下限和上限之间生成随机数是很常见的。 Excel 确实有一个 RANDBETWEEN 函数来执行此操作:

Value = WorksheetFunction.RandBetween(1, 6)

编辑:现在让我们将其放入LboundUbound(假设两者都是整数和Lbound < Ubound

首先,定义:

n = ubound - lbound

接下来,我们将MSDN公式稍作改写:

   Int((ubound - lbound + 1) * Rnd + lbound)
== Int((ubound - lbound + 1) * Rnd) + lbound
== Int(((n + 1) * Rnd)              + lbound

从#3,我们知道Int(((n + 1) * Rnd) 给出了一个介于 0 和 n 之间的随机整数。因此,当您将该随机数添加到下限时,您会得到一个介于下限和上限之间的数字;

   Int(((n + 1) * Rnd) + lbound
== 0...n               + lbound
== lbound...ubound

【讨论】:

  • 所以在我看来,公式可能是Int(Ubound * Rnd + Lbound)
  • 只有当您的LBound 为 0 或 1 时才有效。尝试生成 5 到 10 之间的随机数
  • 那么这些数字是如何工作的?为什么是ubound - lbound + 1?如果你把你的 ubound 和 * RND() 我有点明白了,那么你会得到一个介于 0 和任何值之间的数字。但是,Lbound 是如何计算的呢?
【解决方案2】:

这可能会让它更清楚一点:Rnd 返回一个 0 到

一般来说,Rnd 实际上遵循一个事实标准,即随机数生成器 API 如何在许多(如果不是所有)编程语言中公开(即生成从 0.0 到

话虽如此,许多语言(例如 Python)为核心 Rnd 函数提供了更高级别的包装器,因此在基本场景中使用起来会更容易。 VBA 是一种相当古老的语言——微软很少更新它(它是福也是祸),所以如果你需要一个辅助函数,你必须自己做。

这里你可以改用:

Function RndBetween(lowerbound As Int, upperbound As Int) As Int
    RndBetween = Int((upperbound - lowerbound + 1) * Rnd + lowerbound)
End Function

在你的代码中它变得很简单:

RndBetween(1, 6)

一段时间后,您将拥有一个辅助函数模块,这将使生活更轻松,代码更具可读性。在那之前... StackOverflow :-)

【讨论】:

  • 好消息要知道,很有趣,但它仍然无助于帮助程序中的数字来自哪里。我做了很多编码,并且绝对熟悉缩短方法的助手,但我仍然想知道 + this - That * 和 - 来自哪里。我不知道它是如何工作的。
  • @user1759942 好吧,但这只是数学。如果您将变量名称替换为 x、y、z 等...并将其作为公式写在一张纸上——您的视觉效果可能比 VBA 代码更好。很难按原样阅读。它还可能有助于在控制台中打印一些实例的数字表示 - 只是为了看看它是如何计算的。
【解决方案3】:

使用 RndBetween 之类的公式,例如 make_random_old = CLng((up - down + 1) * Rnd + down)

这是非常错误的(我生命中的 30 分钟调试是理解它的代价!):)

您可以在此处使用 Sub TestMe 来检查原因:

Public Sub testme()

    Dim l_counter       As Long
    Dim l_random        As Long

    For l_counter = 0 To 10000
        l_random = make_random_old(0, 2)
        If l_random = 3 Then Debug.Print l_random
    Next l_counter

    Debug.Print "END"

End Sub

Public Function make_random(down As Long, up As Long) As Long

    make_random = CLng((up - down + 1) * Rnd + down)

    If make_random > up Then make_random = up
    If make_random < down Then make_random = down

End Function

Public Function make_random_old(down As Long, up As Long) As Long

    make_random_old = CLng((up - down + 1) * Rnd + down)

End Function

作为 RndBetweem 中一些随机的解决方法,使用 make_random - 代码中的第二个函数。 它将为您节省很多问题。 :)

【讨论】:

    【解决方案4】:

    @Code Different 已经有正确答案了。这只是为那些乍一看不明白的人准备的

    1. Excel 只生成 0 到 1 之间的随机数
    2. 通过将步骤 1 中生成的随机数乘以一个数字 x,我们可以得到一个介于 0x 之间的值

    那么

    Int ((upperbound - lowerbound + 1) * Rnd + lowerbound)

    在上下界之间生成一个随机数

    1. 在最后一步中,您提供了与步骤 1 中生成的随机数相乘的数字 x。在这里,要生成此数字 x,您需要执行 upperbound - lowerbound,以便 random_number 来自 0产生两个数字的差,即 (upperbound - lowerbound)。现在,如果将较小的数字,即 lowerbound 添加到 random_number,它将产生大于 lowerbound 的总和小于 upperbound

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多