1

Possible Duplicate:
Generating random integer from a range

I just started learning C++ and I'm trying to generate a random integer thats either 1, 2, or 3. I searched around and all the examples I see of generating random numbers are confusing and always different from the last example I looked at. Is there a simple way to do this?

Community
  • 1
  • 1
Petefic
  • 657
  • 6
  • 14
  • 31
  • Now would be a very good time to accept an answer, as you got two good answers and you won't get any better answers for this simple question. Note that abandoning a question because you solved it yourself is just bad practice. – Christian Rau Oct 11 '11 at 00:32

2 Answers2

9

The modulo solution is the most straightforward but it usually loses randomness as modulo as the tendency to "eat up" the lowest bits of the result.

A more random way is to map [0,1[ over [a,b[ in a linear way:

int roll(int min, int max)
{
   // x is in [0,1[
   double x = rand()/static_cast<double>(RAND_MAX+1); 

   // [0,1[ * (max - min) + min is in [min,max[
   int that = min + static_cast<int>( x * (max - min) );

   return that;
}

A generic version is trivially derived from these to get a roll( T min, T max) version.

Joel Falcou
  • 6,247
  • 1
  • 17
  • 34
  • Appears to be a small bug in this implementation -- let `rand()` return `RAND_MAX` and `x` will become `1.0` (so the range is actually [0,1] *inclusive*) causing `that` to exceed the function's specified range by 1. In other words `roll(0,2)` usually returns 0 or 1 but very occasionally will return 2. :) –  Jun 09 '14 at 00:49
  • snap! dividing by RAND_MAX+1 then is probably better. – Joel Falcou Jun 09 '14 at 06:57
  • Discovered this while testing out different PRNGs for a terrain generator and kept on getting this [one white tile](http://i.imgur.com/2kdw0V0.png). Since we haven't implemented "snow" yet, it seemed out of place. :) –  Jun 09 '14 at 20:23
8

Try this:

srand(time(NULL));

int randNum = (rand() % 3) + 1; // you don't need the (...) surrounding rand() % 3 but it helps for clarity

This works by taking the remainder of the return value of the rand function divided by three (which can be 0, 1, or 2) and adding one (to come up with either 1, 2, or 3).

Make sure you include the cstdlib and ctime headers.

Also, call srand only one time, not each time you generate a random number.

Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249
  • 1
    It is `` in C++ – Puppy May 05 '11 at 01:50
  • 7
    This mistakes keeps getting repeated again and again and again. The problem is that it feed of itself and is just so common around the web it is hard to iradicate. This is the standard **anti-pattern** for generating a random number in a range. There are two problems. 1) The bottom bits from rand() are less random than the top bits (% basically uses the bottom bits). 2) Unless the divisor (3 in this case) is an exact factor of RAND_MAX the last few values are slightly less probable than the other values (thus skewing your probability). – Martin York May 05 '11 at 07:00
  • A better solution is: `randNum = (rand() * 1.0 / RAND_MAX * 3) + 1` – Martin York May 05 '11 at 07:02
  • 2
    @Martin: you can't state as a fact that bottom bits are less random. That used to be a problem in the eighties. And your "better alternative" doesn't solve the skewed probability. If you need bullet-proof random-number generation, use the Boost stuff, or C++11. For beginners, this is sufficient. – MSalters May 05 '11 at 07:17
  • 2
    Absolutely a better solution is to use Boost random number generator it was written by people who actually understand the problems associated with random numbers. Actually the solution I present (not mine) does solve the skew problem (notice it uses real numbers not integers). Also yes the bad random distribution of the bottom bits is an old problem that has been made better. But unless you know what rand is doing you can't tell if it has been solved in your variant of rand(). Thus it is more portable to air on the side of safety and write code that will work everywhere. – Martin York May 05 '11 at 07:52