快速安全地确定范围内的随机数

时间:2011-06-17 05:40:18

标签: c++ algorithm random sampling

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

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

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

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

    return(ret);
}

*安全地说,我的意思是统一分布。

2 个答案:

答案 0 :(得分:6)

如果您希望对结果进行统一分布,则拒绝抽样是可行的方法。众所周知,做任何更聪明的事情是很困难的。例如,使用模运算符会导致任何不是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;
}

在你们的共识中你可以读到:

  

算法有点棘手。它拒绝会导致分布不均匀的值(由于2 31 不能被 n 整除)。值被拒绝的概率取决于n。最坏的情况是 n = 2 30 +1,其中拒绝的概率是1/2,并且循环终止之前的预期迭代次数是2。

答案 1 :(得分:-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;
}