5

I created a test application that generates 10k random numbers in a range from 0 to 250 000. Then I calculated MAX and min values and noticed that the MAX value is always around 32k...

Do you have any idea how to extend the possible range? I need a range with MAX value around 250 000!

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Francesco Bonizzi
  • 5,142
  • 6
  • 49
  • 88

5 Answers5

10

This is according to the definition of rand(), see:

http://cplusplus.com/reference/clibrary/cstdlib/rand/

http://cplusplus.com/reference/clibrary/cstdlib/RAND_MAX/

If you need larger random numbers, you can use an external library (for example http://www.boost.org/doc/libs/1_49_0/doc/html/boost_random.html) or calculate large random numbers out of multiple small random numbers by yourself.

But pay attention to the distribution you want to get. If you just sum up the small random numbers, the result will not be equally distributed.

If you just scale one small random number by a constant factor, there will be gaps between the possible values.

Taking the product of random numbers also doesn't work.

A possible solution is the following:

1) Take two random numbers a,b
2) Calculate a*(RAND_MAX+1)+b

So you get equally distributed random values up to (RAND_MAX+1)^2-1

Heinzi
  • 5,793
  • 4
  • 40
  • 69
  • 3
    The product won't be linear either. And your last solution should be `a * (RAND_MAX + 1) + b`. (It will work for random values in the range `[0, (RAND_MAX+1)*(RAND_MAX+1))`, providing there's no overflow. – James Kanze Mar 19 '12 at 18:18
3

Presumably, you also want an equal distribution over this extended range. About the only way you can effectively do this is to generate a sequence of smaller numbers, and scale them as if you were working in a different base. For example, for 250000, you might 4 random numbers in the range [0,10) and one in range [0,25), along the lines:

int
random250000()
{
    return randomInt(10) + 10 * randomInt(10)
        + 100 * randomInt(10) + 1000 * randomInt(10)
        + 10000 * randomInt(25);
}

For this to work, your random number generator must be good; many implementations of rand() aren't (or at least weren't—I've not verified the situation recently). You'll also want to eliminate the bias you get when you map RAND_MAX + 1 different values into 10 or 25 different values. Unless RAND_MAX + 1 is an exact multiple of 10 and 25 (e.g. is an exact multiple of 50), you'll need something like:

int
randomInt( int upperLimit )
{
    int const limit = (RAND_MAX + 1) - (RAND_MAX + 1) % upperLimit;
    int result = rand();
    while ( result >= limit ) {
        result = rand();
    return result % upperLimit;
}

(Attention when doing this: there are some machines where RAND_MAX + 1 will overflow; if portability is an issue, you'll need to take additional precautions.)

All of this, of course, supposes a good quality generator, which is far from a given.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Why not just make `randomInt` recursive if `upperLimit` is over RAND_MAX, and not bother with the needlessly slow `random250000()`? (Or at _least_ give `randomInt` an `assert` to prevent invalid input. – Mooing Duck Mar 19 '12 at 18:31
  • 2
    @That's a possibility. My goal wasn't to provide an optimal solution, but rather to suggest a workable approach; I chose `10` simply because everyone (I hope) is familiar with base 10 arithmetic, and would recognize the underlying idea. Also: you have to watch out when `limit` in `randomInt` becomes large; you can end up throwing away a significant percentage of the results of `rand()`. – James Kanze Mar 19 '12 at 18:38
1

You can just manipulate your number bitwise by generating smaller random numbers.

For instance, if you need a 32-bit random number:

int32 x = 0;
for (int i = 0; i < 4; ++i) { // 4 == 32/8
   int8 tmp = 8bit_random_number_generator();
   x <<= 8*i; x |= tmp;
}

If you don't need good randomness in your numbers, you can just use rand() & 0xff for the 8-bit random number generator. Otherwise, something better will be necessary.

Stefan Marinov
  • 570
  • 4
  • 14
  • Actually, if `RAND_MAX` is of the form `2^n-1` (often the case), `rand() & 0xFF` will not introduce any bias. (Of course, the way the implementation gets a `RAND_MAX` of this form may introduce bias.) – James Kanze Mar 19 '12 at 18:31
  • correct, but it's faster to use the `RAND_MAX` than any `8bit_random_number_generator` – Mooing Duck Mar 19 '12 at 18:32
  • You are both right, I was just pointing out a different implementation. If you use rand() at all, chances are you aren't going for really tight constraints, but you could of course need at least less run time. The best solution is just to use a good external library like [Boost](http://www.boost.org/doc/libs/1_49_0/doc/html/boost_random.html). – Stefan Marinov Mar 19 '12 at 18:40
  • @MooingDuck Maybe. If you end up throwing out a significant number of values returned from `rand()`, it might not be so fast. And then, there's the problem of proving that your algorithm is reasonably correct. At some point, you have to ensure that the number of values whatever the algorithm produces is an exact multiple of the number of values desired, or there will be some bias. – James Kanze Mar 19 '12 at 18:42
0

Scale your numbers up by N / RAND_MAX, where N is your desired maximum. If the numbers fit, you can do something like this:

unsigned long long int r = rand() * N / RAND_MAX;

Obviously if the initial part overflows you can't do this, but with N = 250000 you should be fine. RAND_MAX is 32K on many popular platforms.

More generally, to get a random number uniformly in the interval [A, B], use:

A + rand() * (B - A) / RAND_MAX;

Of course you should probably use the proper C++-style <random> library; search this site for many similar questions explaining how to use it.


Edit: In the hope of preventing an escalation of comments, here's yet another copy/paste of the Proper C++ solution for truly uniform distribution on an interval [A, B]:

#include <random>

typedef std::mt19937 rng_type;
typedef unsigned long int int_type;  // anything you like

std::uniform_int_distribution<int_type> udist(A, B);
rng_type rng;

int main()
{
    // seed rng first:
    rng_type::result_type const seedval = get_seed();
    rng.seed(seedval);

    int_type random_number = udist(rng);
    // use random_number
}

Don't forget to seend the RNG! If you store the seed value, you can replay the same random sequence later on.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • `(rand()*RAND_MAX+rand())/(RAND_MAX*RAND_MAX/250000);`? – Mooing Duck Mar 19 '12 at 18:12
  • 1
    The most frequent value of `RAND_MAX` is something like 2^31 (although obviously, that's not the case he's encountering). And something like `rand() * N / RAND_MAX` will not give an equal distribution: without forcing anything to floating point, there will be a large number of holes, and even doing the intermediate calculations in floating point, then casting back to integer, you can never get more than `RAND_MAX` different values. – James Kanze Mar 19 '12 at 18:22
  • 1
    Your "more generally" algorithm doesn't generally work. The probability that `rand() * (B - A)` overflows is large. On my Linux box, it will overflow as soon a `(B - A) > 1`. (Another problem is that you should be using `RAND_MAX + 1` everywhere, since that's the number of different values `rand()` can return. Except, of course, that on my Linux box, `RAND_MAX + 1` overflows.) – James Kanze Mar 19 '12 at 18:23
  • @JamesKanze: That's all fine and well. Proper answers about `` have been posted many times, which I mentioned, and this is nothing but a quick shot at a user who seems to be content with `rand()` for now. Everyone is invited to look up ``. – Kerrek SB Mar 19 '12 at 18:25
  • @KerrekSB The advice about looking up `` is good. The standard `rand()` is often not particularly good. – James Kanze Mar 19 '12 at 18:29
  • @KerrekSB For the rest, his problem is getting random numbers in an interval greater than `[0,RAND_MAX]`. There's no way a single call to `rand()` will do for that. – James Kanze Mar 19 '12 at 18:32
0

Are you using short ints? If so, you will see 32,767 as your max number because anything larger will overflow the short int.

0-0
  • 482
  • 4
  • 11