views:

204

answers:

5

Hello!

I am taking a course on programming, and we're using C++. We had an assignment where, at some point, we needed to code a function that would return a random number in an [upper, lower] interval. I used the following:

lower + (int) (upper * (rand() / (RAND_MAX + 1.0)));

I did not forget to change srand by using srand((unsigned int) time(0)).

However, I get the same value every time! I asked my professor for help and he, after some investigation, found out that the first number generated by rand() isn't that random... The higher order bits remained unchanged, and since this implementation uses them, the end result isn't quite what I expected.

Is there a more elegant, yet simple solution than to discard the first value or use remainders to achieve what I want?

Thanks a lot for your attention!

~Francisco

EDIT: Thank you all for your input. I had no idea rand() was such a sucky RNG :P

+2  A: 

Given that rand() is not a very strong random number generator, the small amount of bias added by the standard approach is probably not an issue: (higher-lower) needs to be smaller than MAX_RAND of course.

lower + rand() % (higher-lower+1);

fixed off by one error.

Chris Becke
`lower + rand() % (higher-lower+1);`
IVlad
It would be `lower + rand() % (higher-lower + 1);`Out of academic curiosity, I'd like to get a different solution to this problem, but thanks for your input. :)
Francisco P.
+1  A: 

rand() is not a good random-number generator. In addition to the problem you observed it's period length can be very short.

Consider using one of the gsl random number generators.

honk
Thanks for that link!
Francisco P.
+1  A: 

Depending on what OS your are using you may have random() available in addition to rand(). This generates much better pseudo-random numbers than rand(). Check <stdlib.h> and/or man 3 random.

Paul R
+1  A: 

Your code is good, but you should substitute

lower + (int) upper * (rand() / (RAND_MAX + 1.0));

with

lower + (int) (upper - lower + 1)*(rand() / (RAND_MAX + 1.0));

The following code works nicely on my machine:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define lower 10
#define upper 20

int main(void)
{
    int i;
    int number;

    srand(time(0));
    for(i=0; i<10; i++)
    {
        number = lower + (int) (upper - lower + 1)*(rand() / (RAND_MAX + 1.0));
        printf ("%d\n", number);
    }

    return 0;
}    

Of course, since time(0) gives the current time in seconds, two executions within the same second give the same result.

Federico Ramponi
"rand() gives the current time in seconds" - That's an odd implementation. :P
Bill
@Bill: Oh, er, well... it's still an undocumented feature. Top secret. Don't tell anybody
Federico Ramponi
+1  A: 

C++0x random number library (also available in TR1 and Boost) finally solves some nasty issues of rand. It allows getting real randomness (random_device) that you can use for proper seeding, then you can use a fast and good pseudo random generator (mt19937), and you may apply a suitable distribution to that (e.g. uniform_int for min-max range with equal probability for each value).

It also does not use global hidden state like rand() does, so there won't be any issues in multi-threaded programs.

Due to all the modularity it is a bit more difficult to use than simply calling rand, but still the benefits greatly outweigh the steeper learning curve.

Tronic