【问题标题】:Using Doubles Internally to Generate a Random Integer在内部使用双精度数生成随机整数
【发布时间】:2012-03-24 17:22:55
【问题描述】:

我发布了一堆开源随机数生成器on my site,包括一个正态分布的随机数生成器。要生成 10-20 范围内的随机整数,我会写类似 new NormalRandomGenerator(10, 20).Next() 的内容。

有人发表了这条评论:

只是想知道是否有必要在中实现“int Next()” “double NextDouble()”的术语,作为 int 到 double 转换(和 反之亦然)在某些硬件上可能非常慢,包括最近的 PC 硬件,虽然我不是特别了解最新的 CPU 目前。

我相信这条评论指的是当有人在我的一个班级上调用 Next(20) 时,在内部,该调用会转换为 (int)someMersenneTwister.NextDouble() * 20 之类的东西(我不记得我是否使用了四舍五入)。

我以这种方式实现它是因为 MT 既快速又高效(尽管它有一个巨大的随机周期)。据我了解,这是生成随机数的标准方法——调用Next(),它返回 [0 .. 1) 范围内的双精度数,然后相乘并转换为 int。

我的设计有什么问题吗?有没有更好的方法(性能更高、速度更快)来生成不使用双精度数的整数随机数?

对不起,如果这听起来含糊不清。我不确定这里是否有问题。

【问题讨论】:

  • 我什至不明白有限范围内的整数如何具有正态/高斯分布。此分布在整个实轴上返回连续值。
  • 总是可以屏蔽较小数字的位,我想这会更快。除此之外,我一无所获。
  • 对于给定间隔中的 uniform 整数,请检查 my questionmy random library

标签: c# random


【解决方案1】:

不是您问题的答案(因为它在当前形式的 IMO 中没有意义)。但是查看您的代码,我发现了许多错误和其他问题:

  1. 播种。您随时间播种,这会在几毫秒内创建多个UniformRandomGenerators 时导致种子冲突。你从System.Random继承了这个问题。
  2. MersenneTwister.NextDouble 是低质量的。 double 有大约 53 个数字,你只填 32。几乎和填 31 的 System.Random 一样糟糕。
  3. MersenneTwister.Next(int maxValue) 现在将坏的两倍延伸到所需的时间间隔。如果间隔很长,这可能会导致强烈的偏差。 System.Random 有一个非常相似的问题。
  4. Next(int minValue, int maxValue) 在计算 maxValue-minValue 时包含 int 溢出
  5. NormalRandomGenerator 的构造函数计算平均值为this.Mean = ((max - min) / 2) + min;。这是一个整数除法,因此如果max-min 是奇数,则会导致偏差。奇怪的选择,因为 this.Mean 是双精度。
  6. 计算正态分布数的代码看起来也很奇怪,但我不能帮你,因为我不知道它应该做什么。

如果您想生成统一的随机整数,这是我自己的问题的重复:Generating uniform random integers with a certain maximum,它专注于有效地创建这些整数而不引入偏差。我建议将我的答案与 LukeH 的答案结合起来。

【讨论】:

  • 将所有问题放在一起的出色答案!
  • 很棒的代码审查,谢谢。但就像你说的,不是我问题的答案。
  • @ashes999 如果您指定您真正想要的,我们可以回答这个问题。但目前你要求一些不可能/荒谬的东西。
  • @CodeInChaos 真的吗?好的,如果您觉得是这种情况,请随意 DV。
  • @ashes999 我更愿意解释一下你真正想要什么。即你想要什么分布。某种高斯近似(因为你显然不能有一个真正的高斯),但你需要指定你想要如何近似,以及如何计算标准偏差(你当前的计算没有任何意义) .
【解决方案2】:

通过缩放范围 [0..1) 中的双精度来生成随机整数很好,只要生成的双精度足够均匀分布。然而,包括 Mersenne Twister 在内的大多数伪随机数生成器本身都会生成(32 位无符号)整数,因此如果我们不需要将往返次数加倍,那就太好了。

如果边界 N 是 2 的幂,我们可以先生成一个 32 位的随机整数 X 并取 X mod N。这样可以保证产生均匀分布的结果。但是如果 N 不是 2 的幂,取模会在结果分布中产生偏差(例如,X mod 7 为 0 的 32 位无符号整数比 6 多。)如果 N 很小,检测到这样的偏差需要大量生成的数字,但从理论上讲,分布是不正确的。

要为 N 不是 2 的幂生成在 [0..N) 范围内具有真正均匀分布的整数,我们可以求助于采样算法:首先计算 M 使得它是大于 2 的最小幂N(对于 N = 13,M = 16 等等)。然后生成一个 32 位整数 X,计算 Y = X mod M。现在,如果 Y = N,则丢弃它并生成另一个,直到出现 Y

哪种方法最快?只有分析会告诉我们。这取决于硬件、语言和代码质量。

可以在 Knuth 的 TAOCP 第 2 部分中找到更深入的讨论。

【讨论】:

    【解决方案3】:

    您可以使用“Random.Next 方法”:

    http://msdn.microsoft.com/en-us/library/system.random.next.aspx

    您将获得一个小于指定最大值的非负随机数,或者给出一个数字范围(最小值和最大值)

    问候。

    【讨论】:

    • 返回质量相当低的数字。它可能使用NextDouble*max 算法。至少这可以解释它的偏见。
    猜你喜欢
    • 2011-02-11
    • 2012-05-16
    • 2018-11-27
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-20
    相关资源
    最近更新 更多