39

The following code outputs a random number each second:

int main ()
{
    srand(time(NULL)); // Seeds number generator with execution time.

    while (true)
    {
        int rawRand = rand();

        std::cout << rawRand << std::endl;

        sleep(1);
    }
}

How might I size these numbers down so they're always in the range of 0-100?

LihO
  • 41,190
  • 11
  • 99
  • 167
Maxpm
  • 24,113
  • 33
  • 111
  • 170

9 Answers9

85

If you are using C++ and are concerned about good distribution you can use TR1 C++11 <random>.

#include <random>

std::random_device rseed;
std::mt19937 rgen(rseed()); // mersenne_twister
std::uniform_int_distribution<int> idist(0,100); // [0,100]

std::cout << idist(rgen) << std::endl;
Blastfurnace
  • 18,411
  • 56
  • 55
  • 70
  • 21
    While this is correct way of getting a uniform distribution of random numbers, this doesn't answer MaxPM's question which asks nothing about getting a good distribution but asks "How do I scale down numbers from rand()". – dr jimbob Sep 20 '13 at 14:35
  • `random_device` will not always work: It retuns 34992116121 every time in my case. – AbcAeffchen Sep 11 '14 at 19:25
  • 1
    @AbcAeffchen: That's unfortunate, what compiler/version are you using? You might be seeing the same issue as [this other SO question](http://stackoverflow.com/questions/18880654/why-do-i-get-same-sequence-for-everyrun-with-stdrandom-device-with-mingw-gcc4). – Blastfurnace Sep 11 '14 at 20:07
  • I'm using gcc 4.9.1 (64 bit version). Thanks for the link. – AbcAeffchen Sep 11 '14 at 20:11
  • @AbcAeffchen: I don't have 4.9.1 to test but I know it works on [gcc 4.8.1](http://ideone.com/CjZCAS) and Visual C++ 2010-2013. I googled for issues with gcc and `std::random_device` but found nothing, sorry. – Blastfurnace Sep 11 '14 at 20:28
  • thanks. I tested some more. I dont know whats different, but now it works... Sorry for bringing this up. – AbcAeffchen Sep 11 '14 at 20:42
  • This is not a good way to seed a mt19937, you only give it 32 bits of entropy but it can take much more. The right way would be to make an `int[mt19937::state_size]`, using `generate_n` with a `random_device` to fill it with randomness, making a `seed_seq` from that array and then constructing the mersenne twister engine from that `seed_seq`. – Charles Milette Apr 12 '19 at 13:07
32

All the examples posted so far actually give badly distributed results. Execute the code often and create a statistic to see how the values become skewed.

A better way to generate a real uniform random number distribution in any range [0, N] is the following (assuming that rand actually follows a uniform distribution, which is far from obvious):

unsigned result;
do {
    result = rand();
} while (result > N);

Of course, that method is slow but it does produce a good distribution. A slightly smarter way of doing this is to find the largest multiple of N that is smaller than RAND_MAX and using that as the upper bound. After that, one can safely take the result % (N + 1).

For an explanation why the naive modulus method is bad and why the above is better, refer to Julienne’s excellent article on using rand.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 1
    Actually, that a PRNG yields uniformly distributed numbers should be somethnig you can assume. The slightly smarter way can be found in `java.util.Random#nextInt(int)` for example. – Joey Nov 16 '10 at 15:59
  • 3
    You can easily do much, much better by doing `while(result > (RAND_MAX - RAND_MAX % N))` and then dividing by `RAND_MAX/N`. You throw away far fewer numbers for small N but keep the uniform distribution. – Adam Rosenfield Nov 16 '10 at 16:01
  • @Joey: the Java way is incredibly smart but kind of hard to explain and I wouldn’t expect a beginner (or even intermediate) programmer with no special knowledge in statistics to understand it. I think that my way, while giving a correct distribution, is still fairly easy to explain and implement. – Konrad Rudolph Nov 16 '10 at 16:04
  • @Adam: This is the “slightly smarter way” that I explained, without giving the code. I don’t understand, though, why you would divide by `RAND_MAX/N`. Just using `% (N+1)` should surely be fine? – Konrad Rudolph Nov 16 '10 at 16:06
  • @Konrad: as explained in the Java docs: if the underlying random source is a LCG, as is often the case, then its less-significant bits have greater correlation and lower period than its more-significant bits. Scaling ensures that the more-significant bits have a "stronger" effect on the result. Modulus preserves as many less-significant bits as the number of times the divisor is divisible by 2. If the underlying source were truly random, then it wouldn't matter. – Steve Jessop Nov 16 '10 at 16:12
  • @Steve: oh true, forgot about that one. – Konrad Rudolph Nov 16 '10 at 16:18
  • 3
    While this is definitely true; the effect is very slight. RAND_MAX is at least 32677 and on my machine is 2,147,483,647. For the minimum RAND_MAX that means each number in the range 0-77 occurs 327 times while numbers in 78-99 occur only 326 times making them 0.3% less likely. For my machine's RAND_MAX the difference is numbers 0-47 are 0.000 005% more likely than numbers 48-99. For most needs (e.g., outside of serious Monte Carlo modelling) a simple modulus will work just fine. – dr jimbob Nov 16 '10 at 16:39
  • I think you want to take the "largest multiple of N+1", not a multiple of N? – Paŭlo Ebermann May 03 '14 at 08:02
  • 1
    The link to "using `rand`" (eternallyconfuzzled dot com) is broken and now points to a spam blog about buying Youtube views. – nyanpasu64 Nov 30 '19 at 05:36
  • 1
    @jimbo1qaz Thanks, I’ve replaced it with an archived copy. – Konrad Rudolph Dec 01 '19 at 17:55
27

int rawRand = rand() % 101;

See (for more details):

rand - C++ Reference

Others have also pointed out that this is not going to give you the best distribution of random numbers possible. If that kind of thing is important in your code, you would have to do:

int rawRand = (rand() * 1.0 / RAND_MAX) * 100;

EDIT

Three years on, I'm making an edit. As others mentioned, rand() has a great deal of issues. Obviously, I can't recommend its use when there are better alternatives going forward. You can read all about the details and recommendations here:

rand() Considered Harmful | GoingNative 2013

Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
  • 21
    Please don’t use that method in practice – it’s bad. – Konrad Rudolph Nov 16 '10 at 15:56
  • 1
    Note that you'll get a slightly uneven distribution from that. Lower numbers occur a bit more often this way. For a good way to solve this, take a look at `java.util.Random#nextInt(int)`. – Joey Nov 16 '10 at 15:57
  • 4
    Like I said before, using the modulo method isn't quite a perfect random. 100 numbers, and uint has 648 complete ranges of 0-100, and one range of 0-87. Numbers from 0-87 thus have a slightly better chance to occur than numbers from 88-100. – Alex Nov 16 '10 at 15:58
  • Note that `rawRand` will exhibit some bias if you use this technique (assuming that 101 isn't a factor of `RAND_MAX`). – LukeH Nov 16 '10 at 15:59
  • 2
    For people that NEED random numbers, they will not be using rand to generate them. the distortions introduced by modulus and rescaling range adjustments are only significant if you actually had a random distribution in the first place. – Michael Shaw Nov 16 '10 at 23:10
  • 1
    (rand() / RAND_MAX) performs integral division. Since RAND_MAX >= rand(), this value is equal to 1 or 0 (very likely 0), thus this will only produce the values 0 or 100. To fix this you need to make one of the operands a double by casting it. – tyree731 Nov 19 '10 at 21:16
  • 3
    -1. You'll still get a non-uniform distribution. `rand()` has RAND_MAX+1 values; unless it's a multiple of 101 (which it probably isn't), there is no way to assign them to 101 buckets without one of them being bigger. – tc. Jun 20 '11 at 01:58
  • 1
    @Blastfurnace's answer's look like almost like STL's. I gave an upvote to that one (not this one). – Csaba Toth Sep 06 '13 at 20:52
  • 1
    Anybody care to enlighten me as to what the hell just happened? I've wanted to delete the answer forever but can't since it's accepted. I'll gladly admit that it's not the best solution. – Justin Niessner Sep 06 '13 at 21:30
  • 1
    @JustinNiessner, STL's talk on GoingNative 2013 happened. There's a link to a site where the video will be uploaded to soon. – Griwes Sep 06 '13 at 21:41
  • @Borgleader - Just saw the link. Waiting for the video (even though I was told long ago exactly why I was wrong...even though the OP didn't mention distribution). I'd change the answer, but that obviously is the wrong solution. Hello rock and hard place, glad to be stuck between you. – Justin Niessner Sep 06 '13 at 21:44
  • Since your edit, this is not really an answer any more. You need to suggest an alternative implementation yourself. – user207421 Sep 07 '13 at 01:20
  • 1
    @JustinNiessner: I asked Maxpm to switch answers and he's gracefully agreed. You can delete this answer as desired now. Lucky you to be the center of this attention. ;) – GManNickG Sep 07 '13 at 20:04
6

You can do

cout << rawRand % 100 << endl; // Outputs between 0 and 99

cout << rawRand % 101 << endl; // outputs between 0 and 100

For the people downvoting; note one minute after this was originally posted I left the comment:

From http://www.cplusplus.com/reference/clibrary/cstdlib/rand "Notice though that this modulo operation does not generate a truly uniformly distributed random number in the span (since in most cases lower numbers are slightly more likely), but it is generally a good approximation for short spans."

With 64-bit ints and using 100 numbers as output, the numbers 0-16 are represented with 1.00000000000000000455 % of the numbers (an relative accuracy to identically distributed of 1% by about 10-18), while the numbers 17-99 are represented with 0.99999999999999999913 % of the numbers. Yes, not perfectly distributed, but a very good approximation for small spans.

Also note, where does the OP ask for identically distributed numbers? For all we know these are being used for purposes where a small deviations doesn't matter (e.g., anything other than cryptography -- and if they are using the numbers for cryptography this question is much too naive for them to be writing their own cryptography).

EDIT - For people who are truly concerned with having a uniform distribution of random numbers the following code works. Note this isn't necessarily optimal as with 64-bit random ints, it will require two calls of rand() once every 10^18 calls.

unsigned N = 100; // want numbers 0-99
unsigned long randTruncation = (RAND_MAX / N) * N; 
// include every number the N times by ensuring rawRand is between 0 and randTruncation - 1 or regenerate.
unsigned long rawRand = rand();

while (rawRand >= randTruncation) {
    rawRand = rand();  
// with 64-bit int and range of 0-99 will need to generate two random numbers
// about 1 in every (2^63)/16 ~ 10^18 times (1 million million times)

// with 32-bit int and range of 0-99 will need to generate two random numbers 
// once every 46 million times.

}
cout << rawRand % N << stdl::endl;
dr jimbob
  • 17,259
  • 7
  • 59
  • 81
  • 2
    From http://www.cplusplus.com/reference/clibrary/cstdlib/rand/ "Notice though that this modulo operation does not generate a truly uniformly distributed random number in the span (since in most cases lower numbers are slightly more likely), but it is generally a good approximation for short spans." – dr jimbob Nov 16 '10 at 15:50
  • On MSVC, RAND_MAX is still 32767, so no 32 or 64 bits anywhere. – Thomas Weller Oct 18 '22 at 20:00
3

See man 3 rand -- you need to scale by dividing by RAND_MAX to obtain the range [0, 1] after which you can multiply by 100 for your target range.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • Interesting. Does this method have any advantages over the modulus method? – Maxpm Nov 16 '10 at 15:52
  • It yields statistically "better" values than using modulo. – Simone Nov 16 '10 at 15:56
  • 3
    Well, depending how rubbish `rand()` is to start with. It's usually pretty rubbish, though. – Steve Jessop Nov 16 '10 at 15:57
  • 10
    No. The unevenness is just spread differently. But you still get some numbers more often than others. – Joey Nov 16 '10 at 15:57
  • 2
    +1 and I'm a little surprised this is the only answer to suggest division by `RAND_MAX` rather than `%` modulus. – aschepler Nov 16 '10 at 16:01
  • 3
    @Joey: the point is that it avoids the most heinous of the bad behaviours that are seen in practice. For instance LCGs where the least significant bit alternates on successive samples. So if you take a modulus with an even number, your values will have the same property. If you scale, they'll at least dodge that bullet. The thing to remember about `rand()` is that it is allowed to be an atrocious PRNG. Any use of it is suspect if good random numbers are required, but some are even more suspect than others. – Steve Jessop Nov 16 '10 at 16:01
-2

For the range min to max (inclusive), use: int result = rand() % (max - min + 1) + min;

Jake Petroules
  • 23,472
  • 35
  • 144
  • 225
-5

How long an answer would you like.

the simplest is to convert using the remainder when divided by 101:

int value = rawRand % 101;

A semipurist would rescale using doubles:

double dbl = 100 * ((double)rawRand / RAND_MAX);
int ivalue = (int)(dbl + 0.5);   // round up for above 0.5

And a purist would say that rand does not produce random numbers.

For your info, the quality of random numbers is measured by taking a sequence of numbers and then calculating the mathematical probability that the source of that sequence was random. The simple hack using the remainder is a very poor choice if you are after randomness.

Michael Shaw
  • 604
  • 7
  • 15
-6

rawRand % 101 would give [0-100], inclusive.

Costique
  • 23,712
  • 4
  • 76
  • 79
  • This would leave them non-random. Uniformity of distribution tests fail unless modulo is performed on an appropriate range, or the divisor is on the order of a power of 2. – ingyhere Mar 28 '14 at 03:52
-6

Some people have posted the following code as an example:

int rawRand = (rand() / RAND_MAX) * 100;

This is an invalid way of solving the problem, as both rand() and RAND_MAX are integers. In C++, this results in integral division, which will truncate the results decimal points. As RAND_MAX >= rand(), the result of that operation is either 1 or 0, meaning rawRand can be only 0 or 100. A correct way of doing this would be the following:

int rawRand = (rand() / static_cast<double>(RAND_MAX)) * 100;

Since one the operands is now a double, floating point division is used, which would return a proper value between 0 and 1.

tyree731
  • 453
  • 3
  • 8
  • 4
    This is only partly true and still does not generate uniformly distributed number, for `rawRand == 100` is very unlikely since only `RAND_MAX` "produces" it. – Micha Wiedenmann Sep 11 '13 at 11:32