The C++11 std library has several random number generators (RNG), each implementing the concept UniformRandomNumberGenerator. These can then be used as argument for random distributions, see also this documentation for an overview.
The advantage of this design is that the choice of the underlying RNG engine is de-coupled from its application. However, the design also requires the definition (not merely the declarations) of all calls to the RNG to be available (if the RNG type is to remain unspecified as template parameter). Thus, in
struct complicated_random_distribution
{
/*
some data and auxiliary methods here
*/
// complicated; may call RNG::operator() many times
template<typename RNG>
some_type operator()(RNG&gen) const;
};
the member operator()
cannot be straightforwardly implemented in a separate compilation unit (CU), but must be available in the same header file (or one #include
d from it).
For a separate implementation, one ideally would want some way to pack a RNG in the same way as std::function<>
packs any callable object.
(Simply using std::function
and providing the values for RNG::min()
and RNG::max()
as arguments to a function defined in a separate CU is restrictive and will not allow to use, say, std::uniform_real_distribution<>
inside).
How can this be done? Are implementations for this available? Will the std library provide this in the future? Or am I after a red herring?
Edit Random number generators are required to have static
members min()
and max()
, making type-erasure hard or impossible (GNU's libstdc++ doesn't make this assumption and a type erasure with non-static members min()
and max()
works, but not with LLVM's libc++, which uses the standard required static
members). Is there a way to still solve this problem? If not, doesn't this imply that the C++ standard has a botched interface for random number generators?
It is possible to hack into the Random Number Generators used in casinos and other fields. But, it is a difficult venture that even the best hackers find challenging. With high-quality RNGs and security protocols, this possibility can be reduced to the minimum.
The RAND function in Google Sheets generates a random number between 0 and 1 and can be used as a random number generator in Google Sheets. The RAND function outputs a decimal number between 0 and 1, for example, 0.2760773217.
The RAND function in Excel is one of the two functions specially designed for generating random numbers. It returns a random decimal number (real number) between 0 and 1. RAND() is a volatile function, meaning that a new random number is generated every time the worksheet is calculated.
Adapt the RNG with an independent_bits_engine
, and type erase the adapted RNG. You have full knowledge of what the independent_bits_engine
's min()
and max()
are.
Here's a sketch:
struct RNG_wrapper {
using result_type = std::uint32_t;
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return 0xFFFFFFFF; }
template<class RNG>
using my_engine_type = std::independent_bits_engine<RNG, 32, result_type>;
template<class RNG,
class = std::enable_if_t<!std::is_same<std::decay_t<RNG>, RNG_wrapper>{}>>
RNG_wrapper(RNG&& r)
: rng(my_engine_type<std::decay_t<RNG>>(std::forward<RNG>(r))) {}
result_type operator()() { return rng(); }
std::function<result_type()> rng;
};
This works in clang and gcc (with libstdc++), but this is not strictly a UniformRandomNumberGenerator
, for the noted reason that min
and max
are not static.
#include <cassert>
#include <random>
#include <functional>
#include <iostream>
template<typename T>
class AnyUniformRandomNumberGenerator
{
T mMin;
T mMax;
std::function<T()> mValue;
public:
using result_type = T;
template<typename UniformRandomNumberGenerator>
AnyUniformRandomNumberGenerator(UniformRandomNumberGenerator uniformRandomNumberGenerator) :
mMin(UniformRandomNumberGenerator::min()),
mMax(UniformRandomNumberGenerator::max()),
mValue([=]() mutable { return uniformRandomNumberGenerator(); })
{}
T operator()()
{
return mValue();
}
T min()
{
return mMin;
}
T max()
{
return mMax;
}
};
int main()
{
std::default_random_engine rng;
AnyUniformRandomNumberGenerator<decltype(rng())> any{rng};
assert(any() <= any.max());
assert(any() >= any.min());
std::uniform_int_distribution<> dist{1, 6};
std::cout << dist(any);
}
GCC: http://rextester.com/ANAP79935
clang http://rextester.com/YCIIR21607
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With