【问题标题】:Get a pseudorandom float number in a closed interval [a, b]得到一个闭区间的伪随机浮点数 [a, b]
【发布时间】:2011-08-23 18:41:23
【问题描述】:

我想知道使用 Ruby rand 内核函数(请不要使用 Random 模块)在封闭区间内获取伪随机浮点数的最佳方法。

举个例子,我将使用闭区间 [0.0, 7.7](区间中包含 0.0 和 7.7),但任何其他浮点区间也应该是有效的。

对于区间 [0.0, 7.7],下一个解无效

rand * 7.7

为什么?

如果你调用 rand 没有参数,你会得到一个大于或等于 0.0 且小于 1.0 的伪随机浮点数。那么之前的解决方案可以给我们的浮点数范围是多少呢?

rand 将返回 [0.0, 0.9999999...] 范围内的伪随机浮点数

0.0 * 7.7
=> 0.0          # Correct!

0.9999999 * 7.7
=> 7.69999923   # Incorrect!

区间与 [0.0, 7.7] 不匹配。

有人知道这个问题的优雅解决方案吗?

谢谢!

【问题讨论】:

    标签: ruby random floating-point


    【解决方案1】:

    有一个Random 类可以做你想做的事:

    generator = Random.new # You need to instance it
    generator.rand 0.0..7.7
    

    (文档说明 0.0..7.7 和 0.0...7.7 之间的差异将被考虑在内。)

    在未来的 1.9.3 中,您将能够将范围传递给 Kernel#randRandom.rand(您已经可以在预览版中这样做)。

    【讨论】:

    • 如果这行得通,那么它很酷,但从文档中并不完全清楚它对待 0.0..7.7 与 0.0...7.7 的区别(即它会在请求时包含端点)。以下是文档:ruby-doc.org/core/classes/Random.html#M000693 无论如何我们可以在合理的时间内测试该类,看看它是否有时会返回端点?
    • 您已链接到 Random.rand。 Random#rand 说“prng.rand(5.0..9.0) #=> 介于 5.0 和 9.0 之间,包括 9.0”。查看 C 代码,将使用两个不同的函数(generate_real 代表 0...1.0,generate_real2 代表 0..1.0)。
    • 哦,你是对的,如果你看对了地方,文档就很清楚了(当然是公共实例方法)。
    • 谢谢你。我不知道 Random#rand 可以使用范围,但我想知道如何使用 Kernel#rand 解决这个问题。对于新的 1.9.3 版本来说,这是一个很酷的功能,范围将包含在 Kernel#rand 中。
    • 我会检查这个解决方案是否正确,因为它是最红宝石的,我会用它来解决我的问题。谢谢!。
    【解决方案2】:

    我会这样做:

    Fineness = 2**64
    puts rand(Fineness+1)*7.7/Fineness
    

    每当rand 返回它的最大可能值时,您将得到Fineness*7.7/Fineness,结果恰好等于 7.7(但我不完全确定这将永远是这种情况,因为浮点数是不精确的)。

    只要 Fineness 中的位数多于您计算机上的 double,那么我相信您不会注意到结果分布有任何异常。

    【讨论】:

    • David 我认为使用您的解决方案,您永远不会得到 0.0,并且该解决方案必须包含闭合区间,即返回值中包含 0.0 和 7.7 的 [0.0, 7.7]。谢谢。
    • 我认为您误读了我的解决方案。 rand(Fineness+1)rand(Fineness)+1 不同。每当rand 返回 0 时,我的解决方案都会给你 0.0。
    【解决方案3】:

    怎么样:

    (rand/0.9999999999999999...)*7.7

    基本上,通过最大可能的随机数对随机数进行归一化。这样,您将创建范围 [0..1]。

    但是,我不确定如何获得最大数字,在 ruby​​ 中小于 1.0。

    【讨论】:

    • 我认为这可能是一个可能的解决方案,但正如您所说,您需要知道函数 rand 可以返回的最大数以正确规范化它(也许我们可以使用一个非常大的数字,即 0.999999999999999999999 但我不知道这是否正确)。
    【解决方案4】:

    为什么需要这个?我不知道是否需要将其作为真正的单精度或双精度数。另一方面,在实际情况下,您可能需要 0.0 到 7.7 之间的数字,增量为 0.1。在这种情况下,您可以使用成熟的技术从 0 变为 77,然后除以 10。

    【讨论】:

      【解决方案5】:

      根据您需要的精度位数,您可以使用四舍五入的方法来捕捉到边缘的间隔边界。希望这会有所帮助。

      这是来自Wikipedia的文字

      四舍五入到偶数一个更不偏颇的打破平局规则是 四舍五入到偶数,即

      如果 y 的分数是 0.5,那么 q 是最接近 y 的偶数。 因此,例如,+23.5 变为 +24,+22.5 变为 +22,-22.5 变为 -22,-23.5 变为 -24。

      这种方法也对称地对待正负值, 因此,如果原始数字是 正面或负面的概率相等。此外,对于大多数 y 值的合理分布,预期(平均值)值 四舍五入的数字与原始数字基本相同 数字,即使后者都是正数(或全负数)。 然而,这条规则仍然会引入一个积极的偏见,即使 数字(包括零)和奇数的负偏差。

      这种四舍五入法的变体也称为无偏法 四舍五入(模棱两可,有点滥用),收敛四舍五入, 统计学家的四舍五入、荷兰四舍五入、高斯四舍五入或 银行家的四舍五入。这在簿记中被广泛使用。

      这是 IEEE 754 计算函数中使用的默认舍入模式 和运算符。

      【讨论】:

      • Jeremy 你能举个例子来说明你的想法吗?谢谢。
      猜你喜欢
      • 2021-02-17
      • 2023-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-08
      • 2011-07-14
      • 2011-08-30
      相关资源
      最近更新 更多