so in my custom C++ library i wanted to create 2 reliable and simple functions, i for quickly generating a random number, and the other for doing the same thing but within a specified range, i came up with the following but would like to know if they are good:
int random()
{
std::random_device rd;
std::uniform_int_distribution<int>dist;
return dist(rd);
}
int randomWithinRange(int range)
{
std::random_device rd;
std::uniform_int_distribution<int>dist;
return (dist(rd) % range);
}
the functions work and compile alright, i just want to know how good they would be for long term inclusion
Related
I have a function that calls srand and rand like this:
void foo() {
int seed = some_operation();
std::srand(seed);
int value = std::rand();
// Do something with random value
}
However, I don't want to change the global state of rand. Whats the easiest way to get a random number then?
Requirements:
random number must be deterministic based on seed
C++11 is fine
foo should be thread safe
the global state of rand should not be modified
Edit:
There is a stackoverflow question asking how to generate random numbers. The accepted answer however shows how to generate truly unique random numbers, using a slow std::random_device. I just needed a simple generator using a fixed seed instead.
C++11 is fine
Then use the new pseudorandom number library:
#include <random>
int foo() {
int seed = some_operation();
std::minstd_rand rand(seed);
int value = rand();
// Do something with random value
}
minstd_rand is a simple linear congruential engine, similar to that typically used by std::rand(), but with its state encapsulated in a class. Other engines are available, if you need a higher quality pseudorandom sequence. The Mersenne Twister, std::mt19937, is usually a good choice if you don't have specific requirements.
<random> defines a number of PRNG classes that you can use, which do not use global states.
For example, using a default Mersenne Twister, std::mt19937:
#include <iostream>
#include <random>
int main() {
int seed = 1234;
std::mt19937 rng(seed);
std::cout << "Random number: " << rng() << std::endl;
}
One approach is to provide your own implementation, with its own seed data. A template for doing that is provided in the manpage for rand().
static unsigned long next = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned seed) {
next = seed;
}
I'm trying to generate a random number using rand() command, but each time i get very similar numbers.
This is my code:
#include <iostream>
#include <time.h>
using namespace std;
int main()
{
srand(time(0));
cout << rand();
return 0;
}
I ran it 5 times and the numbers i got are:
21767
21806
21836
21862
21888
How can i make the numbers be more different?
From the documentation of rand:
There are no guarantees as to the quality of the random sequence produced. In the past, some implementations of rand() have had serious shortcomings in the randomness, distribution and period of the sequence produced (in one well-known example, the low-order bit simply alternated between 1 and 0 between calls).
rand() is not recommended for serious random-number generation needs. It is recommended to use C++11's random number generation facilities to replace rand().
It (and I) recommend to use the newer c++11 random number generators in <random>.
In your specific case it seems you want a std::uniform_int_distribution. An example, as given on the linked page is:
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> distrib(1, RAND_MAX);
std::cout << distrib(gen) << '\n';
Those three lines of generating random number looks a bit tricky. It is hard to always remember those lines. Could someone please shed some light on it to make it easier to understand?
#include <random>
#include <iostream>
int main()
{
std::random_device rd; //1st line: Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //2nd line: Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> dis(1, 6);
for (int n=0; n<10; ++n)
std::cout << dis(gen) << ' '; //3rd line: Use dis to transform the random unsigned int generated by gen into an int in [1, 6]
std::cout << '\n';
}
Here are some questions I can think of:
1st line of code:
random_device is a class as described by the documentation random_device, so this line means declaring a object rd? If yes, why in 2nd line we pass rd() to construct mt19937 instead of using the object rd (without parentheses)?
3rd line of code:
Why do call class uniform_int_distribution<> object dis()? Is dis() a function? Why shall we pass in gen object into dis()?
random_device is slow but genuinely random, it's used to generate the 'seed' for the random number sequence.
mt19937 is fast but only 'pseudo random'. It needs a 'seed' to start generating a sequence of numbers. That seed can be random (as in your example) so you get a different sequence of random numbers each time. But it could be a constant, so you get the same sequence of numbers each time.
uniform_int_distribution is a way of mapping random numbers (which could have any values) to the numbers you're actually interested in, in this case a uniform distribution of integers from 1 to 6.
As is often the case with OO programming, this code is about division of responsibilities. Each class contributes a small piece to the overall requirement (the generation of dice rolls). If you wanted to do something different it's easy because you've got all the pieces in front of you.
If this is too much then all you need to do is write a function to capture the overall effect, for instance
int dice_roll()
{
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<> dis(1, 6);
return dis(gen);
}
dis is an example of a function object or functor. It's an object which overloads operator() so it can be called as if it was a function.
std::random_device rd; // create access to truly random numbers
std::mt19937 gen{rd()}; // create pseudo random generator.
// initialize its seed to truly random number.
std::uniform_int_distribution<> dis{1, 6}; // define distribution
...
auto x = dis(gen); // generate pseudo random number form `gen`
// and transform its result to desired distribution `dis`.
I am given to believe that random number generators (RNGs) should only be seeded once to ensure that the distribution of results is as intended.
I am writing a Monte Carlo simulation in C++ which consists of a main function ("A") calling another function ("B") several times, where a large quantity of random numbers is generated in B.
Currently, I am doing the following in B:
void B(){
std::array<int, std::mt19937::state_size> seed_data;
std::random_device r;
std::generate(seed_data.begin(), seed_data.end(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); //perform warmup
std::mt19937 eng(seq);
std::uniform_real_distribution<> randU(0,1);
double myRandNum = randU(eng);
//do stuff with my random number
}
As you can see, I am creating a new random number generator each time I call the function B. This, as far as I can see, is a waste of time - the RNG can still generate a lot more random numbers!
I have experimented with making "eng" extern but this generates an error using g++:
error: ‘eng’ has both ‘extern’ and initializer extern std::mt19937 eng(seq);
How can I make the random number generator "global" so that I can use it many times?
Be careful with one-size-fits-all rules. 'Globals are evil' is one of them. A RNG should be a global object. (Caveat: each thread should get its own RNG!) I tend to wrap mine in a singleton map, but simply seeding and warming one up at the beginning of main() suffices:
std::mt19937 rng;
int main()
{
// (seed global object 'rng' here)
rng.dispose(10000); // warm it up
For your usage scenario (generating multiple RNs per call), you shouldn't have any problem creating a local distribution for each function call.
One other thing: std::random_device is not your friend -- it can throw at any time for all kinds of stupid reasons. Make sure to wrap it up in a try..catch block. Or, and I recommend this, use a platform specific way to get a true random number. (On Windows, use the Crypto API. On everything else, use /dev/urandom/.)
Hope this helps.
You shouldn't need to pass anything or declare anything, as the interaction between mt19937 and uniform_real_distribution is through globals.
std::array<int, std::mt19937::state_size> seed_data;
std::random_device r;
std::generate(seed_data.begin(), seed_data.end(), std::ref(r));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data)); //perform warmup
std::mt19937 eng(seq);
B()
...
void B()
{
std::uniform_real_distribution<> randU(0,1);
...
C++11 introduced the header <random> with declarations for random number engines and random distributions. That's great - time to replace those uses of rand() which is often problematic in various ways. However, it seems far from obvious how to replace
srand(n);
// ...
int r = rand();
Based on the declarations it seems a uniform distribution can be built something like this:
std::default_random_engine engine;
engine.seed(n);
std::uniform_int_distribution<> distribution;
auto rand = [&](){ return distribution(engine); }
This approach seems rather involved and is surely something I won't remember unlike the use of srand() and rand(). I'm aware of N4531 but even that still seems to be quite involved.
Is there a reasonably simple way to replace srand() and rand()?
Is there a reasonably simple way to replace srand() and rand()?
Full disclosure: I don't like rand(). It's bad, and it's very easily abused.
The C++11 random library fills in a void that has been lacking for a long, long time. The problem with high quality random libraries is that they're oftentimes hard to use. The C++11 <random> library represents a huge step forward in this regard. A few lines of code and I have a very nice generator that behaves very nicely and that easily generates random variates from many different distributions.
Given the above, my answer to you is a bit heretical. If rand() is good enough for your needs, use it. As bad as rand() is (and it is bad), removing it would represent a huge break with the C language. Just make sure that the badness of rand() truly is good enough for your needs.
C++14 didn't deprecate rand(); it only deprecated functions in the C++ library that use rand(). While C++17 might deprecate rand(), it won't delete it. That means you have several more years before rand() disappears. The odds are high that you will have retired or switched to a different language by the time the C++ committee finally does delete rand() from the C++ standard library.
I'm creating random inputs to benchmark different implementations of std::sort() using something along the lines of std::vector<int> v(size); std::generate(v.begin(), v.end(), std::rand);
You don't need a cryptographically secure PRNG for that. You don't even need Mersenne Twister. In this particular case, rand() probably is good enough for your needs.
Update
There is a nice simple replacement for rand() and srand() in the C++11 random library: std::minstd_rand.
#include <random>
#include <iostream>
int main ()
{
std:: minstd_rand simple_rand;
// Use simple_rand.seed() instead of srand():
simple_rand.seed(42);
// Use simple_rand() instead of rand():
for (int ii = 0; ii < 10; ++ii)
{
std::cout << simple_rand() << '\n';
}
}
The function std::minstd_rand::operator()() returns a std::uint_fast32_t. However, the algorithm restricts the result to between 1 and 231-2, inclusive. This means the result will always convert safely to a std::int_fast32_t (or to an int if int is at least 32 bits long).
How about randutils by Melissa O'Neill of pcg-random.org?
From the introductory blog post:
randutils::mt19937_rng rng;
std::cout << "Greetings from Office #" << rng.uniform(1,17)
<< " (where we think PI = " << rng.uniform(3.1,3.2) << ")\n\n"
<< "Our office morale is " << rng.uniform('A','D') << " grade\n";
Assuming you want the behavior of the C-style rand and srand functions, including their quirkiness, but with good random, this is the closest I could get.
#include <random>
#include <cstdlib> // RAND_MAX (might be removed soon?)
#include <climits> // INT_MAX (use as replacement?)
namespace replacement
{
constexpr int rand_max {
#ifdef RAND_MAX
RAND_MAX
#else
INT_MAX
#endif
};
namespace detail
{
inline std::default_random_engine&
get_engine() noexcept
{
// Seeding with 1 is silly, but required behavior
static thread_local auto rndeng = std::default_random_engine(1);
return rndeng;
}
inline std::uniform_int_distribution<int>&
get_distribution() noexcept
{
static thread_local auto rnddst = std::uniform_int_distribution<int> {0, rand_max};
return rnddst;
}
} // namespace detail
inline int
rand() noexcept
{
return detail::get_distribution()(detail::get_engine());
}
inline void
srand(const unsigned seed) noexcept
{
detail::get_engine().seed(seed);
detail::get_distribution().reset();
}
inline void
srand()
{
std::random_device rnddev {};
srand(rnddev());
}
} // namespace replacement
The replacement::* functions can be used exactly like their std::* counterparts from <cstdlib>. I have added a srand overload that takes no arguments and seeds the engine with a “real” random number obtained from a std::random_device. How “real” that randomness will be is of course implementation defined.
The engine and the distribution are held as thread_local static instances so they carry state across multiple calls but still allow different threads to observe predictable sequences. (It's also a performance gain because you don't need to re-construct the engine or use locks and potentially trash other people's cashes.)
I've used std::default_random_engine because you did but I don't like it very much. The Mersenne Twister engines (std::mt19937 and std::mt19937_64) produce much better “randomness” and, surprisingly, have also been observed to be faster. I don't think that any compliant program must rely on std::rand being implemented using any specific kind of pseudo random engine. (And even if it did, implementations are free to define std::default_random_engine to whatever they like so you'd have to use something like std::minstd_rand to be sure.)
Abusing the fact that engines return values directly
All engines defined in <random> has an operator()() that can be used to retrieve the next generated value, as well as advancing the internal state of the engine.
std::mt19937 rand (seed); // or an engine of your choosing
for (int i = 0; i < 10; ++i) {
unsigned int x = rand ();
std::cout << x << std::endl;
}
It shall however be noted that all engines return a value of some unsigned integral type, meaning that they can potentially overflow a signed integral (which will then lead to undefined-behavior).
If you are fine with using unsigned values everywhere you retrieve a new value, the above is an easy way to replace usage of std::srand + std::rand.
Note: Using what has been described above might lead to some values having a higher chance of being returned than others, due to the fact that the result_type of the engine not having a max value that is an even multiple of the highest value that can be stored in the destination type.
If you have not worried about this in the past — when using something like rand()%low+high — you should not worry about it now.
Note: You will need to make sure that the std::engine-type::result_type is at least as large as your desired range of values (std::mt19937::result_type is uint_fast32_t).
If you only need to seed the engine once
There is no need to first default-construct a std::default_random_engine (which is just a typedef for some engine chosen by the implementation), and later assigning a seed to it; this could be done all at once by using the appropriate constructor of the random-engine.
std::random-engine-type engine (seed);
If you however need to re-seed the engine, using std::random-engine::seed is the way to do it.
If all else fails; create a helper-function
Even if the code you have posted looks slightly complicated, you are only meant to write it once.
If you find yourself in a situation where you are tempted to just copy+paste what you have written to several places in your code it is recommended, as always when doing copy+pasting; introduce a helper-function.
Intentionally left blank, see other posts for example implementations.
You can create a simple function like this:
#include <random>
#include <iostream>
int modernRand(int n) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(0, n);
return dis(gen);
}
And later use it like this:
int myRandValue = modernRand(n);
As mentioned here