What is the simplest way to use C++ random library?

Pages: 12
I don't get it when people have to use very long statements to use C++ random library. How do you even remember statements like :

std::size_t seed = std::chrono::system_clock::now().time_since_epoch().count()

Do I need to know it by heart?

Also, can you give me the shortest C++ example how to use C++ random library in way that totally replaces rand()? It might help me in the future.
closed account (E0p9LyTq)
The simplest to learn using the C++ random library?

The examples in the <random> header reference section:
http://www.cplusplus.com/reference/random/

Time related classes and functions are in the <chrono> header:
http://www.cplusplus.com/reference/chrono/

Both C++ libraries above are C++11 additions.

Reading select C++ Standard working papers would help as well, here's one I recommend:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3551.pdf

There are also examples for C++ libraries at cppreference:
http://en.cppreference.com/w/cpp/header/chrono
http://en.cppreference.com/w/cpp/header/random

Gaining more exposure to what the C++ library can do for you makes it easier to understand "complicated" statements.

C-library functions have their place, not every function has a C++ equivalent. Yet when there are C++ versions those should be used.

Two things to note about the rand() and srand() functions:

1. Even the current C Standard recommends not using them if there are alternatives available. C++ has those alternatives.

2. There is a proposal to remove them from C++. No more srand/rand in C++.
Last edited on
I found this code in Internet. Does this replaces rand()?

1
2
3
4
5
6
7
int randPlusPlus(int max)
{
	static unsigned int seed(std::chrono::system_clock::now().time_since_epoch().count());
	static std::mt19937 gen(seed);
	std::uniform_int_distribution<int> dis(0, max - 1);
	return dis(gen);
}


Or am I a lucky person there?
closed account (E0p9LyTq)
That code snippet is one way to replace srand() and rand().

There are many other ways because there are multiple random engines and distributions in the C++ <random> library.

There are almost too many options, especially for a beginner, it is an embarrassment of riches.

The more I play around and use the C++ random features the more I like them for having such a wide range of options to suit any need. From simple random simulations or rolling a die or flipping a coin all the way up to world-class encryption algorithms and beyond.
in a lot of code, you want to debug and test with consistent values.
random number generation functions and classes should be able to produce the same numbers every time during your debugging and turned back over to system timestamps or whatever in production code.

So I would warn you to allow the seed to be set to a constant in your code until you are satisfied with it, then swap the constant to a few values and test, then put it back to that time based data.

rand produces a double. This is not a one to one replacement for that. Generating random doubles is a little more tricksy but its not rocket science either. Also, produce the biggest thing you can... for doubles, produce a tenbyte, for integers, produce a 64 or 128 bit value. Its easy to peel off what you have from a larger value to a smaller size if need be.

Last edited on
Yeah if I can use it for rand() and srand(), I will start with it now.

jonnin : I think I can just change the seed in the case I need fixed results.

But I still love rand and srand because they are only 9 characters long and are easy to remember. And our professors still accept them, so there is little place for me to use C++ random library when learning at university.
@Sanboro, I still like to use srand() and rand() for their sheer simplicity. However, I suspect I will get laughed out of this forum sooner or later if I don't test the choppy waters of the C++11 random library. FWIW my own understanding is that it all boils down to
seed - number generator - probability distribution - individual instance
with you having to set each of those 4 things (the first 3 only once; the last as many times as you need).

can you give me the shortest C++ example how to use C++ random library in way that totally replaces rand()? 


My personal backup program to try to remember how to do this is for percentages of dice rolls (apologies in advance for not putting std:: in front of everything). No idea if this helps.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<random>
#include<chrono>
using namespace std;
 
//======== Random dice roll ==========

mt19937                       diceGenerator   ( chrono::system_clock::now().time_since_epoch().count() );
uniform_int_distribution<int> diceDistribution( 1, 6 );

int diceRoll()
{
   return diceDistribution( diceGenerator );
}

//====================================


int main()
{
   int counts[1+6] = { 0 };
   int nmax;

   cout << "How many rolls? ";    
   cin >> nmax;

   for ( int i = 1; i <= nmax; i++ ) counts[ diceRoll() ]++;

   for ( int j = 1; j <= 6   ; j++ ) cout << j << ": " << 100.0 * counts[j] / nmax << "%\n";
}
Last edited on
The C++ Standard Library (2nd ed), Nicolai Josuttis - chapter 17 (Numerics) - has a good explanation why rand() causes problems and there he also quotes a couple of paragraphs from Accelerated C++, Koenig & Moo - why computing random numbers by rand()%n fails in practice:

if the value of n is large, and the generated maximum value is not evenly divisible by n, some remainders will appear more often than others. For example, if the maximum is 32767 and n is 2000, 17 generated value (500, 2500, ..., 30500, 32500) would map to 500, while only 16 generated values (1500, 2500, ..., 31500) would map to 1500. And this gets worse the larger n is.
This feels like a miss by the C++ guys. They wrote a good random function. Rand does not have any particular implementation attached to it in the standard that I recall (from memory, it had a performance requirement?). Why they did not just replace rand's internal function with the improved version is a huge oversight.

You can easily wrap the convoluted and extensive syntax of the modern functions back into a rand and srand replacement class or stand-alone functions. Actually, a LOT of the modern c++ messy stuff can be wrapped up into much, much simpler looking code.

Agreed about the modulo stuff. Ive been mixing rand up in my head, its not 0-1 values in double, its integers. Thinking of another language... haven't used it in a while, seeing as how I did the above route and rolled my own...


Last edited on
You can't even get something simpler than this, not even with C's rand().

1
2
3
4
5
6
7
8
9
10
11
#include<random>
#include<iostream>

int main(int argc, char ** argv)
{
   std::random_device random;
   std::wcout<<L"A random number:"<<random();

   return EXIT_SUCCESS;
}
Last edited on
The sub-section in Josuttis' book that I quoted above is actually titled 'Don't Use Engines without Distributions' - take a look
closed account (E0p9LyTq)
You can't even get something simpler than this, not even with C's rand().

std::random_device appears to be not properly implemented in at least one major C++ implementation AFAIK, GCC .

I've tried older versions and flavors (5.1, TDM-GCC 4.9.2), and random_device always returned the exact same sequence each time.

I really do like the simplicity of std::random_device, and use it when available, but it can be a pain to test for availability for cross-compiler use.
random_device always returned the exact same sequence each time.

Further quotes for Josuttis:
.. the initial state of an engine is well defined and not random ... if you need nonpredictable random value you have to set the state of the generator randmly by processing some behavior that you can't influence with your code, such as the number of milliseconds between two mouse clicks. That is, you have to pass a so-called seed to the constructor of the engine.
closed account (E0p9LyTq)
@gunnerfunner,

All that quote does is show some implementations do not follow the standard requirements for std:random_device. std::random_device is supposed to produce non-deterministic random numbers by simply instantiating an object. Without any further work without manipulation of the instantiated engine as is required by any of the other random generators, C++ or C.

MSVC++ implements the engine so it works as the standard says it should. In my experience GCC doesn't.

std::random_device is best used as a seed for the other C++ random engines, such as mt19937, because it needs no "warm up" to create random numbers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
std::mt19937 initialize_twister(std::size_t seed = std::chrono::system_clock::now().time_since_epoch().count())
{
   static constexpr std::size_t NUM_DISCARD = 10240;

   std::minstd_rand lcg(seed);
   lcg.discard(NUM_DISCARD);

   std::size_t seeds[std::mt19937::state_size];
   std::generate_n(seeds, std::mt19937::state_size, lcg);

   try
   {
      // check if there is a random_device available
      seeds[0] = std::random_device {}();
   }
   catch (const std::exception&)
   {
      /* ignore */
   }

   std::seed_seq seed_sequence(std::begin(seeds), std::end(seeds));

   return  std::mt19937 {seed_sequence}; // warm-up with seed seed_sequence.generate()
//   return seed_sequence;
}


FurryGuy wrote:
In my experience GCC doesn't.

What target, OS, and gcc version was your experience?

For me, on intel running Linux, current GNU implementation just calls the RDRND CPU instruction, unless I construct it as std::random_device("/dev/random");

in fact, here's the gcc source: https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/src/c++11/random.cc#L79-L110

just noticed
FurryGuy wrote:
older versions and flavors (5.1, TDM-GCC 4.9.2)

Is that what it was? MinGW has a long way to go to catch up to C++11, unfortunately. Boost has a working random_device for Windows.
Last edited on
std::random_device is best used as a seed for the other C++ random engines, such as mt19937, because it needs no "warm up" to create random numbers.

so there's no getting away from some seeding whether one uses std::random_device or std::default_random_engine (which Josuttis was referring to), as cppreference says:
implementations of random_device degrades sharply once the entropy pool is exhausted. For practical use random_device is generally only used to seed a PRNG such as mt19937

http://en.cppreference.com/w/cpp/numeric/random/random_device
closed account (E0p9LyTq)
Cubbi wrote:
MinGW has a long way to go to catch up to C++11, unfortunately

That is why I mentioned my personal experience, so newbies learning to use the C++ random classes and functions don't get caught unaware with the deficiencies of a particular implementation.

As I was. I have admittedly limited knowledge of the compilers available.

Apparently some people, not you Cubbi, don't like hearing about flawed human beings creating less than perfect compilers. They want to argue minutiae.
Apparently some people, not you Cubbi, don't like hearing about flawed human beings creating less than perfect compilers. They want to argue minutiae.

yeah, there are some like them on this forum as well surprisingly!!
std::random_device appears to be not properly implemented in at least one major C++ implementation AFAIK, GCC .


I use GCC on Debian and std::random_device works just fine. However, I don't write programs that require millions of random numbers, but for general stuff it's good enough.
Last edited on
FurryGuy wrote:
flawed human beings creating less than perfect compilers

The first step to fixing a flaw is admitting it.
I see gcc has a bug report for random_device::entropy not working, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67578 but I don't see one regarding random_device constructor being so decidedly non-portable.
On the other hand, MinGW has a bug report for this issue: https://sourceforge.net/p/mingw-w64/bugs/338/ and the last comment says "I have implementation using CryptoAPI, but for gcc-4.6. Sometime I will fix it for gcc-trunk and commit to GCC..." -- that was in 2014. so I just added a comment to that.
Pages: 12