Some C++ questions about using <random>
-
I need to generate random numbers/ordering. I wish to use the
std::
stuff from#include <random>
rather than the Qt random functions. I have 3 questions about behaviour/coding.I have some class of mine into which I wish to put the random functions. I have essentially the following:
// someclass.h class SomeClass { public: int random_int(int range); void shuffle(...); private: static std::mt19937 &random_generator(); }; // someclass.cpp /*static*/ std::mt19937 &SomeClass::random_generator() { static std::random_device rd; static std::mt19937 gen(rd()); return gen; } int SomeClass::random_int(int range) { std::uniform_int_distribution<> distr(0, range); return distr(random_generator()); } void SomeClass::shuffle(...) { std::shuffle(..., random_generator()); }
I have 3 questions:
- All the examples of shuffling/picking a random are self-contained, they perform the
std::random_device rd; std::mt19937 gen(rd());
each time any random thingy (shuffle, pick) is wanted, because the example is standalone and does not cover doing more random operations in the future. However I assume one or both of those statements is "slow". That is why I have factored them into function
SomeClass::random_generator()
, so the generator will be produced once when first called and then re-used in future. Am I right?-
I have implemented that with
static
function variables. Is this reasonable? If you really want me to use instead, say, a singleton pattern please let me know. -
The return result of my
SomeClass::random_generator()
isstd::mt19937
. Inrandom.h
that is atypedef mersenne_twister_engine<...> mt19937;
. I don't like this as it stands because it uses a specificstd::mt19937
type. But other types would be acceptable, e.g. I could change it tomt19937_64
or something else acceptable which isn't even amersenne_twister_engine<>
type. It just has to be usable as parameter tostd::shuffle()
orstd::uniform_int_distribution<>
. I cannot spot some "base type" I could use instead as the return result ofSomeClass::random_generator()
which would allow me to return astd::mt19937
or astd::mt19937_64
or whatever other non-specific types are acceptable. It may be that I need some template definition here? Or what?
-
Hi @JonB
Yes std::random is awful !
For my calculator app, I have implemented a rand function
// definition typedef std::mt19937 RandomGenerator; static RandomGenerator& randomGenerator() { static std::random_device rd; static RandomGenerator gen(rd()); return gen; }
// usage case ExpFunct::Funct_rand: { if(val EQ 0) ThrowException(ExpException::OutOfRange); std::uniform_int_distribution<int> dist(1,val); value.setNumber(dist(randomGenerator())); } break;
-
@mpergand
OK, your code/approach is similar to mine.-
You have indeed used
static std::random_device rd; static RandomGenerator gen(rd());
, so these are only executed once and then re-used. I presume you agree with my impression that they are "expensive" and so should not be re-evaluated each time a random operation is wanted? -
You have used a (
static
) function withstatic
variables for these, e.g. not a singleton pattern, so you are happy with my version which is the same as yours? -
You have not addressed this. I should not have to make the returned generator be of a type as specific as
std::mt19937
. This is not required bystd::shuffle()
orstd::uniform_int_distribution<>
. They would accept e.g.std::mt19937_64
or other quite different types. But I cannot figure from the header file/CPP reference (https://en.cppreference.com/w/cpp/algorithm/random_shuffle, https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution) what I could write more generically as either a base class or a template definition for the return result ofrandom_generator()
which would allow it to returnstd::mt19937
,std::mt19937_64
or other, can you answer that?
Take for example the definition of std::shuffle():
template< class RandomIt, class URBG > void shuffle( RandomIt first, RandomIt last, URBG&& g );
What can I declare the return-type of
random_generator()
so as to match theURBG&& g
parameter?shuffle()
only accepts certain things, e.g. it can't beint
or string, so is there a base/common type? Do I have to write myrandom_generator()
function as some kind of template? How/what? -
-
1 I presume you agree with my impression that they are "expensive" and so should not be re-evaluated each time a random operation is wanted?
This code was writing nearly 10 years ago , so I assume yes :)
2 same as above
3 not sure I can help you at this point, I have never used suffle, let's talk more experts than me.
-
@mpergand said in Some C++ questions about using <random>:
, I have never used suffle
It applies not just to the last parameter to
std::shuffle()
but equally withuniform_int_distribution<>
to thegen
parameter instd::uniform_int_distribution<> distrib(1, 6); std::cout << distrib(gen);
or your use of
dist(randomGenerator())
for that. You and I have made that be typestd::mt19937
, but we shouldn't have to, it works with other types. How can I write that function so that e.g. it might return either astd::mt19937
or astd::mt19937_64
? -
Random number generators are a complicated topic. It depends on the context of your application how to handle random numbers. If you just want any sort of randomness (e.g. for games) any of the approaches work.
However, in a scientific context true uniformity of the generated random numbers is essential. Furthermore, reproducibility of results is also important (this is called Monte Carlo method). Reproducibility is guaranteed by using the same seed every time. Mathematically speaking, only specific seeds are proven to generate a true uniform random number sequence. The last time I have used RNGs C++ didn't have them, yet. So, I have used Tina's RNG: https://www.numbercrunch.de/trng/. Their documentation explains all of this a lot better than I ever could.
Basically, what I am trying to say is that making your RNG static or not comes down to your use case. Do you need a uniform distribution of random numbers over all your uses of the RNG or not? If you don't care, any approach will do and this discussion is more about performance.
-
the only try way to generate random numbers:
https://www.amazon.com/Images-SI-RNG-01-Random-Generator/dp/B00IWH9DPG
-
@SimonSchroeder
Sorry, but I don't think any part of my questions relate to random numbers or generators or distribution/uniformity performance. They are questions about C++ (especially the as-yet-unanswered question #3). With regard to the static-ness/number of times to call the initial "seeding" when comes withstd::random_device rd; std::mt19937 gen(rd());
I only wish to reseed once and then accept the random number which comes from that, as is standard practice with random number generators (e.g. for old-stylerand()
we used to callsrand()
just once).