【问题标题】:Will this random double generator work?这个随机双生成器会工作吗?
【发布时间】:2011-11-14 00:30:37
【问题描述】:

直觉上可以写一个随机双精度生成器如下:

double randDouble(double lowerBound, double upperBound)
{
    double range = upperBound - lowerBound;
    return lowerBound + range * rand();
}

假设我们假设rand() 在区间 [0, 1) 上返回一个均匀分布的伪随机双精度。

此方法是否保证返回 [lowerBound, upperBound) 内具有均匀概率分布的随机双精度数?我特别感兴趣的是浮点计算的性质是否会导致某些范围的最终分布出现峰值或下降。

【问题讨论】:

  • 最好先阅读此维基百科article,因为这是一个“困难”的问题。

标签: language-agnostic random floating-point double probability


【解决方案1】:

首先,rand() 生成 伪随机 数字,而不是真正随机的。因此,我假设您在询问您的函数是否在指定范围内生成伪随机数。

其次,就像 Oli Charlesworth 所说,许多 rand 实现返回一个介于 0 和 RAND_MAX 之间的数字,其中 RAND_MAX 是它可以采用的最大可能值。在这些情况下,您可以使用

获取 [0, 1) 中的值
double r = rand()/((double)RAND_MAX+1);

+1 的存在使得 r 不能为 1。

其他语言的 rand 会返回 0 到 1 之间的值,在这种情况下,您不需要进行上述除法。无论哪种方式,事实证明您的函数会返回一个不错的随机分布近似值。有关详细信息,请参阅以下链接:http://www.thinkage.ca/english/gcos/expl/c/lib/rand.html 请注意,此链接为您提供的功能略有不同,他们声称这些功能更好一些,但您拥有的功能可能已经足够好。

【讨论】:

    【解决方案2】:

    如果您的上限和下限是 2 的相邻幂,那么您得到的分布将与您从 rand() 获得的分布一样好,因为您实际上只是在改变 rand() 给您的指数,不改变尾数。

    如果您想扩展范围以覆盖超过 2 的 1 次方,那么您的方法将永远不会在您的范围的下半部分生成有效的浮点数。 (您实际上是将尾数的一位或多位移动到指数中,而尾数的最低有效位是非随机的。)

    如果您在更一般的范围内使用该方法(例如尾数被计算修改),那么您在尝试将随机整数转换为随机整数时也会遇到相同的不均匀性模 n 而不使用拒绝采样。

    任何生成浮点数均匀分布的正确方法都必须考虑到四舍五入到任何给定浮点数的实数间隔并不总是相同的宽度。在范围的较低部分,浮点数会更密集,因此该范围内的每个单独的浮点数应该比较大的数字选择更少。

    【讨论】:

    • 根据这个正确性的定义,以及我在野外看到的情况,没有人在一个范围内生成均匀随机双精度值的实现是正确的。 :(
    • 那是因为它对大多数用途没有太大影响,并且因为正确执行它可能需要更多随机位(在硬件 RNG 开始出现在主流 CPU 中之前,这很昂贵)。但它的实现很简单:生成一个足够宽的定点随机数以覆盖您正在采样的动态范围,如果它不在您的确切范围内,则拒绝它,然后转换为浮点数。但是,如果您从双精度数的整个范围内进行采样,您最终可能需要一两个千位的随机数据。
    【解决方案3】:

    嗯,不。 rand() 返回一个介于 0 和 RAND_MAX 之间的数字;这种量化会在你的分布中留下很大的漏洞;事实上,几乎所有介于lowerBoundupperBound 之间的浮点值都不会被选中。

    【讨论】:

    • 对不起,我并不是要暗示 rand() 的特定 C 实现,我想的是一个更像 Java 的 Math.random() 的函数。我已经在问题中澄清了这一点。
    • @donnyton:啊,好的。即便如此,这仍然会留下永远不会被选中的值。
    猜你喜欢
    • 2013-07-24
    • 2012-07-08
    • 1970-01-01
    • 2015-12-09
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 2013-02-17
    • 1970-01-01
    相关资源
    最近更新 更多