I know there is a bit of limitations for a random number generation in C++ (can be non-uniform). How can I generate a number from 1 to 14620?
Thank you.
A common approach is to use std::rand() with a modulo:
#include<cstdlib>
#include<ctime>
// ...
std::srand(std::time(0)); // needed once per program run
int r = std::rand() % 14620 + 1;
However, as @tenfour mentions in his answer, the modulo operator can disrupt the uniformity of values std::rand()
returns. This is because the modulo translates the values it discards into valid values, and this translation might not be uniform. For instance, for n
in [0, 10)
the value n % 9
translates 9
to 0
, so you can get zero by either a true zero or a 9 translated to zero. The other values have each only one chance to yield.
An alternative approach is to translate the random number from std::rand()
to a floating-point value in the range [0, 1)
and then translate and shift the value to within the range you desire.
int r = static_cast<double>(std::rand()) / RAND_MAX * 14620) + 1;
Use rand.
( rand() % 100 ) is in the range 0 to 99
( rand() % 100 + 1 ) is in the range 1 to 100
( rand() % 30 + 1985 ) is in the range 1985 to 2014
( rand() % 14620 + 1 ) is in the range 1 to 14620
EDIT:
As mentioned in the link, the randomizer should be seeded using srand
before use. A common distinctive value to use is the result of a call to time
.
srand() / rand()
are the functions you need, as others have answered.
The problem with %
is that the result is decidedly non-uniform. To illustrate, imagine that rand()
returns a range of 0-3. Here are hypothetical results of calling it 4000 times:
0 - 1000 times
1 - 1000 times
2 - 1000 times
3 - 1000 times
Now if you do the same sampling for (rand() % 3)
, you notice that the results would be like:
0 - 2000 times
1 - 1000 times
2 - 1000 times
Ouch! The more uniform solution is this:
int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);
Sorry for the sloppy code, but the idea is to scale it down properly to the range you want using floating point math, and convert to integer.
The rand() function is not really the best Random generator, a better way would be by using CryptGenRandom().
This example should do do the trick:
#include <Windows.h>
// Random-Generator
HCRYPTPROV hProv;
INT Random() {
if (hProv == NULL) {
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT))
ExitProcess(EXIT_FAILURE);
}
int out;
CryptGenRandom(hProv, sizeof(out), (BYTE *)(&out));
return out & 0x7fffffff;
}
int main() {
int ri = Random() % 14620 + 1;
}
Here's a tutorial using the boost library http://www.boost.org/doc/libs/1_45_0/doc/html/boost_random/tutorial.html#boost_random.tutorial.generating_integers_in_a_range
If you've got a c++0x environment, a close derivative of the boost lib is now standard:
#include <random>
#include <iostream>
int main()
{
std::uniform_int_distribution<> d(1, 14620);
std::mt19937 gen;
std::cout << d(gen) << '\n';
}
This will be fast, easy and high quality.
You didn't specify, but if you wanted floating point instead just sub in:
std::uniform_real_distribution<> d(1, 14620);
And if you needed a non-uniform distribution, you can build your own piece-wise constant or piece-wise linear distribution very easily.