Generating random integer from a range

前端 未结 13 1513
失恋的感觉
失恋的感觉 2020-11-22 03:12

I need a function which would generate a random integer in given range (including border values). I don\'t unreasonable quality/randomness requirements, I have four requirem

相关标签:
13条回答
  • 2020-11-22 03:37

    Notice that in most suggestions the initial random value that you have got from rand() function, which is typically from 0 to RAND_MAX, is simply wasted. You are creating only one random number out of it, while there is a sound procedure that can give you more.

    Assume that you want [min,max] region of integer random numbers. We start from [0, max-min]

    Take base b=max-min+1

    Start from representing a number you got from rand() in base b.

    That way you have got floor(log(b,RAND_MAX)) because each digit in base b, except possibly the last one, represents a random number in the range [0, max-min].

    Of course the final shift to [min,max] is simple for each random number r+min.

    int n = NUM_DIGIT-1;
    while(n >= 0)
    {
        r[n] = res % b;
        res -= r[n];
        res /= b;
        n--;
    }
    

    If NUM_DIGIT is the number of digit in base b that you can extract and that is

    NUM_DIGIT = floor(log(b,RAND_MAX))
    

    then the above is as a simple implementation of extracting NUM_DIGIT random numbers from 0 to b-1 out of one RAND_MAX random number providing b < RAND_MAX.

    0 讨论(0)
  • 2020-11-22 03:38

    assume min and max are int values, [ and ] means include this value, ( and ) means not include this value, using above to get the right value using c++ rand()

    reference: for ()[] define, visit:

    https://en.wikipedia.org/wiki/Interval_(mathematics)

    for rand and srand function or RAND_MAX define, visit:

    http://en.cppreference.com/w/cpp/numeric/random/rand

    [min, max]

    int randNum = rand() % (max - min + 1) + min
    

    (min, max]

    int randNum = rand() % (max - min) + min + 1
    

    [min, max)

    int randNum = rand() % (max - min) + min
    

    (min, max)

    int randNum = rand() % (max - min - 1) + min + 1
    
    0 讨论(0)
  • 2020-11-22 03:43

    Let's split the problem into two parts:

    • Generate a random number n in the range 0 through (max-min).
    • Add min to that number

    The first part is obviously the hardest. Let's assume that the return value of rand() is perfectly uniform. Using modulo will add bias to the first (RAND_MAX + 1) % (max-min+1) numbers. So if we could magically change RAND_MAX to RAND_MAX - (RAND_MAX + 1) % (max-min+1), there would no longer be any bias.

    It turns out that we can use this intuition if we are willing to allow pseudo-nondeterminism into the running time of our algorithm. Whenever rand() returns a number which is too large, we simply ask for another random number until we get one which is small enough.

    The running time is now geometrically distributed, with expected value 1/p where p is the probability of getting a small enough number on the first try. Since RAND_MAX - (RAND_MAX + 1) % (max-min+1) is always less than (RAND_MAX + 1) / 2, we know that p > 1/2, so the expected number of iterations will always be less than two for any range. It should be possible to generate tens of millions of random numbers in less than a second on a standard CPU with this technique.

    EDIT:

    Although the above is technically correct, DSimon's answer is probably more useful in practice. You shouldn't implement this stuff yourself. I have seen a lot of implementations of rejection sampling and it is often very difficult to see if it's correct or not.

    0 讨论(0)
  • 2020-11-22 03:46

    I recommend the Boost.Random library, it's super detailed and well-documented, lets you explicitly specify what distribution you want, and in non-cryptographic scenarios can actually outperform a typical C library rand implementation.

    0 讨论(0)
  • 2020-11-22 03:53

    Here is an unbiased version that generates numbers in [low, high]:

    int r;
    do {
      r = rand();
    } while (r < ((unsigned int)(RAND_MAX) + 1) % (high + 1 - low));
    return r % (high + 1 - low) + low;
    

    If your range is reasonably small, there is no reason to cache the right-hand side of the comparison in the do loop.

    0 讨论(0)
  • 2020-11-22 03:55
    int RandU(int nMin, int nMax)
    {
        return nMin + (int)((double)rand() / (RAND_MAX+1) * (nMax-nMin+1));
    }
    

    This is a mapping of 32768 integers to (nMax-nMin+1) integers. The mapping will be quite good if (nMax-nMin+1) is small (as in your requirement). Note however that if (nMax-nMin+1) is large, the mapping won't work (For example - you can't map 32768 values to 30000 values with equal probability). If such ranges are needed - you should use a 32-bit or 64-bit random source, instead of the 15-bit rand(), or ignore rand() results which are out-of-range.

    0 讨论(0)
提交回复
热议问题