2

I am having trouble getting rand() to work in C++. rand() normally gives me a very large number. When I try to use the modulo operator (%) to give it a range, it always returns 0, no matter what.

Seeding the random number generator at the beginning of the program doesn't help either.

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • 13
    Can you post some of the code you're using? – fbrereto Jan 25 '10 at 01:33
  • 4
    Doesn't rand() give you a number between 0 and 1, so you have to multiply it before applying the modulo? – slugster Jan 25 '10 at 01:35
  • @slugster - rand() is consistently giving me a number above 10000000. – Zachary Hinchliffe Jan 25 '10 at 01:35
  • 3
    @slugster: No. rand() in C/C++ gives a number between 0 and RAND_MAX, which is guaranteed to be at least 32767. – LiraNuna Jan 25 '10 at 01:36
  • See http://www.cplusplus.com/reference/clibrary/cstdlib/rand/ for an example how to use rand(). – Chris O Jan 25 '10 at 01:39
  • Ahh, i stand corrected. It has been more than 10 years since i did anything with C/C++ :) – slugster Jan 25 '10 at 01:51
  • 4
    @slugster: Then you really should not be offering advice. Its not as if I offer my advice to equestrian riders. – Martin York Jan 25 '10 at 02:02
  • 1
    Incidentally, avoid using `%` to generate random numbers in a range. http://c-faq.com/lib/randrange.html – jamesdlin Jan 25 '10 at 02:07
  • 1
    @Martin York - i agree, i wouldn't teach people how to ride horses either. I wasn't giving advice though, i asked a question. Sorry if it annoyed you. – slugster Jan 25 '10 at 02:26
  • @slugster: That's what we call a rhetorical question. Its not really a question. It is a statement masked as a question. Adding the question mark at the end does not change it. – Martin York Jan 25 '10 at 02:37
  • 1
    It was quite obviously a question. – Lightness Races in Orbit Jan 07 '13 at 16:25
  • without a [mcve] no one can correctly answer that. It's probably that you're using a trashy RNG like Apple's default one [Why does rand() % 7 always return 0?](https://stackoverflow.com/q/7866754/995714), [Rand() % 14 only generates the values 6 or 13](https://stackoverflow.com/q/20263187/995714) – phuclv Mar 04 '19 at 23:55

3 Answers3

8

I think this is common if the random generator algorithm leaves a certain pattern of bits as zero. (For example, if the low-order bits are zero, the number mod some low constant will always be zero.)

Maybe you should try something like:

const int desired_maximum = /* ... */;

int r = (((double)rand()) / RAND_MAX) * desired_maximum;

For example in this manpage link, it says:

In Numerical Recipes in C: The Art of Scientific Computing (William H. Press, Brian P. Flannery, Saul A. Teukolsky, William T. Vetterling; New York: Cambridge University Press, 1992 (2nd ed., p. 277)), the following comments are made:

"If you want to generate a random integer between 1 and 10, you should always do it by using high-order bits, as in

j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
and never by anything resembling
j = 1 + (rand() % 10);
(which uses lower-order bits)."
asveikau
  • 39,039
  • 2
  • 53
  • 68
  • 1
    It wouldn't be a very good PNRG if it always returned multiples of N :-) – paxdiablo Jan 25 '10 at 01:55
  • 4
    Please don't blindly recommend the high-order bits. This is entirely dependent on the PRNG used. Numerical Recipes is a fine book but especially the older editions are full of dangerous advice. This is one of those instances. Besides, even those C/C++ implementations that use an LCG *do* throw away the low-order bits. People have learned since the 70s. – Joey Jan 25 '10 at 07:41
  • 1
    @paxdiablo, if *N* is 1, then I'd have no problem with that ;-) – Joey Jan 25 '10 at 07:46
  • Well, in that case you don't really need a RNG; there's just not that many choice in numbers between 1 and N when N==1 ;) – MSalters Jan 25 '10 at 12:36
  • @msa: well, it returns *multiples* of *N*, so 1 is actually the best you can get there :-) – Joey Jan 25 '10 at 14:35
7

The following code works just fine for me (emitting a random number between 0 included and 1000 excluded each time it's run):

#include <cstdlib>
#include <ctime>
#include <iostream>

int main()
{
    std::srand(time(0));
    std::cout<<(std::rand() % 1000)<<std::endl;
    return 0;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
5

It appears that your immediate problem has been dealt with, but I think it's still worth mentioning one more point. Using the remainder to clamp outputs from rand to a specified range will usually cause bias in the results. To be specific, if the range of the generator (RAND_MAX in the case of C or C++) isn't a multiple of the range you're clamping to, some outputs will occur more often than others. For comparison, consider trying to divide 11 candies evenly between 3 children (without breaking any into pieces). The only way you can do it is NOT hand out some of the candy. Likewise, with a random number generator, the only way to get an even distribution in your output is not use some of the inputs.

int rand_lim(int limit) {
/* return a random number between 0 and limit inclusive.
 */
    int divisor = RAND_MAX/(limit+1);
    int retval;

    do { 
        retval = rand() / divisor;
    } while (retval > limit);

    return retval;
}

As asveikau pointed out in his post, you generally want to use the upper bits from a typical linear congruential generator. The lower bits are generally more predictable. By dividing instead of taking a remainder, this retains upper bits. Though this does have a while loop, it often executes only once, and rarely more than twice, so its impact on performance is pretty minimal.

Whether this is worthwhile depends on the use you're making of the numbers you generate -- if you want dice or cards for a game that your kids will play a couple of times, using a remainder generally won't hurt a thing. If you're trying to do some sort of Monte Carlo simulation (for example) you probably want to be a bit more careful though...

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Java's `java.util.Random.nextInt(int)` also has a very interesting implementation of an unbiased choice of a random number between 0 and *n*. As for the high-order bits ... see my comment on asveikau's answer. I really haven't seen a libc in a while that handed out the real low-order bits of the state word. And there are generators that have weak high-order bits. C doesn't guarantee you an LCG for `rand()`. – Joey Jan 25 '10 at 07:45
  • @Johannes:C doesn't guarantee much of anything about rand() -- in fact, at one time it had a really poor generator as an example, and wording that apparently convinced at least a few implementers that a better generator wasn't allowed. Nonetheless, lower-order bits being worse than higher order bits is sufficiently common that keeping the higher order bits is a good rule of thumb. While some implementations of rand() throw out some lower order bits, 1) it's often insufficient, and 2) a few still don't. – Jerry Coffin Jan 25 '10 at 14:09
  • And a few generators have weak high-order bits. Where results will be worse than what you began with. The best advice for C would probably be to avoid the built-in RNG completely since it isn't specified anywhere and you could get anything from WELL to RANDU. Still, a lot of people don't understand anything about random numbers and generalizations of the "Never do this" sort are harmful in those cases. In general meddling with generators without a clue only makes matters worse, not better. – Joey Jan 25 '10 at 14:34