简体   繁体   English

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

[英]Quickly and safely determine random number within range

How would I quickly and safely * determine a random number within a range of 0 (inclusive) to r (exclusive)? 如何快速 安全地确定0 (含)到r (不含)范围内的随机数?

In other words, an optimized version of rejection sampling: 换句话说,拒绝采样的优化版本:

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

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

    return(ret);
}

*By safely, I mean a uniform distribution. *安全地说,我的意思是统一分配。

Rejection sampling is the way to go if you want to have a uniform distribution on the result. 如果要对结果进行均匀分布,可以采用拒绝抽样法。 It is notoriously difficult to do anything smarter. 众所周知,做任何更聪明的事情都很难。 Using the modulo operator for instance results in an uneven distribution of the result values for any number that's not a power of 2. 例如,对于任何非2的幂的数字,使用模运算符都会导致结果值的不均匀分布。

The algorithm in you post however can be improved by discarding the unnecessary most significant bits. 但是,可以通过丢弃不必要的最高有效位来改进您发布的算法。 (See below.) (见下文。)

This is how the standard Java API implements Random.nextInt(int n) : 这就是标准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;
}

And in the commens you can read: 在命令中,您可以阅读:

The algorithm is slightly tricky. 该算法有些棘手。 It rejects values that would result in an uneven distribution (due to the fact that 2 31 is not divisible by n ). 它拒绝会导致分布不均的值(由于2 31不能被n整除)。 The probability of a value being rejected depends on n. 值被拒绝的概率取决于n。 The worst case is n =2 30 +1, for which the probability of a reject is 1/2, and the expected number of iterations before the loop terminates is 2. 最坏的情况是n = 2 30 +1,拒绝的概率是1/2,循环终止之前的预期迭代次数是2。

u32 myrand(u32 x)
{
    return rand() % (x+1);
}

Since the question has been changed to include even distribution, this would need something more like this: 由于该问题已更改为包括均匀分布,因此将需要更多类似以下内容:

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM