【问题标题】:Quickly and safely determine random number within range快速安全地确定范围内的随机数
【发布时间】:2011-09-16 22:18:21
【问题描述】:

我将如何快速安全地*确定0(包括)到r(不包括)范围内的随机数?

换句话说,拒绝抽样的优化版本:

u32 myrand(u32 x)
{
    u32 ret = rand();

    while(ret >= x)
        ret = rand();

    return(ret);
}

*安全,我的意思是均匀分布。

【问题讨论】:

  • 这个之前已经讨论过,有一些很好的答案,但是我找不到链接ATM。我确实记得(1)有一个网页详细批评了处理这个问题的常用方法,给出了“正确”的方法,(2)有一个强大的标准库(tr1、boost 或 C+ +0x) 来处理各种随机数分布,使用一个不错的(基于 Mersenne Twistor 的?)生成器。
  • @steve314:您可以制作 Boost、TR1 C++0x。他们都有uniform_int
  • 已找到链接 - stackoverflow.com/questions/4195958/random-number-from-0-to-100 - 请参阅 Konrad Rudolph 和 Blastfurnace 的回答。
  • -1 rand() 通常与加密安全相去甚远,以至于使分布更加统一并没有那么有用。
  • @tc rand() 是一个示例函数,它清楚地显示了意图。你宁愿我写BlumBlumShub()来迷惑大家吗?此外,这不是 -1 的理由。

标签: c++ algorithm random sampling


【解决方案1】:
u32 myrand(u32 x)
{
    return rand() % (x+1);
}

由于问题已更改为包括均匀分布,因此需要更多类似的内容:

u32 myrand(u32 x)
{
   assert(x <= RAND_MAX && x > 0);
   int numOfRanges = (RAND_MAX % x);
   int maxAcceptedRand = numOfRanges * x;
   int randNumber;
   do
   {
      randNumber = rand();
   }
   while(randNumber <= maxAcceptedRand);
   return number / numOfRanges;
}

【讨论】:

  • 这会导致结果值的分布不均匀,除非x+1 是 2 的偶数次幂。
  • 使用拒绝抽样的全部意义在于避免这种情况。
  • 好的,很公平。他编辑了问题以包括均匀分布。我安全地认为它一定不会像在 x 值较低的拒绝情况下那样陷入几乎无限循环。
  • 几乎!你的意思可能是numOfRanges = RAND_MAX/x,但正确的方法更像numOfRanges = (RAND_MAX+1)/x,但为了可靠地避免溢出,你需要做一些更像RAND_MAX/x + (RAND_MAX%x == x-1 ? 1 : 0)的事情(或者只使用uint64_t)。
  • 哦,是的,除法不取模。抱歉没有尝试代码。我在工作,编译时有几分钟的空闲时间。整个事情的弱点是它都是基于 rand() 函数。它可能会在其范围内均匀分布,但在多次调用中它的行为不像真正的随机源。
【解决方案2】:

如果您想对结果进行均匀分布,那么拒绝抽样是一种可行的方法。众所周知,做任何更聪明的事情都是困难的。例如,使用模运算符会导致任何不是 2 的幂的数字的结果值分布不均匀。

但是,您发布的算法可以通过丢弃不必要的最高有效位来改进。 (见下文。)

This is how标准Java API实现Random.nextInt(int n)

public int nextInt(int n) {

    [...]

    if ((n & -n) == n)  // i.e., n is a power of 2
        return (int)((n * (long)next(31)) >> 31);

    int bits, val;
    do {
        bits = next(31);
        val = bits % n;
    } while (bits - val + (n-1) < 0);

    return val;
}

您可以在评论中阅读:

算法有点棘手。它拒绝会导致不均匀分布的值(因为 231 不能被 n 整除)。一个值被拒绝的概率取决于 n。最坏的情况是 n=230+1,拒绝的概率是 1/2,循环终止前的预期迭代次数是 2。

【讨论】:

    猜你喜欢
    • 2015-12-20
    • 2011-12-16
    • 1970-01-01
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    相关资源
    最近更新 更多