We have uniform_int_distribution and uniform_real_distribution, wouldn't it be possible to have an encompassing uniform_distribution , which specializes in float/double and int/..., when specified?
1 Answer
AFAIU, the comments above by @user877329 and @revolver_ocelot explain this correctly, and the other answer is completely wrong.
It is wrong to unify the interfaces of uniform_int and uniform_real, not because they are implemented differently (which can be solved via template specialization), but because the interfaces mean different things.
Suppose we unify the interfaces (using a variation of the suggestion in the other answer), like so:
template <typename T> using uniform_distribution = typename std::conditional< std::is_integral<T>::value, std::uniform_int_distribution<T>, std::uniform_real_distribution<T> >::type; Then if we define uniform_distribution<some_type> u(0, 9), the meaning is very different:
if
some_typeis integral, then u will output 9 approximately 1/10ths of the time.if
some_typeis not, thenuwill never output 9.
The following code (whose output is true and then false) illustrates this:
#include <random> #include <iostream> #include <type_traits> template <typename T> using uniform_distribution = typename std::conditional< std::is_integral<T>::value, std::uniform_int_distribution<T>, std::uniform_real_distribution<T> >::type; int main() { std::random_device rd; std::mt19937 gen(rd()); { uniform_distribution<int> u(0, 9); bool over_found = false; for(size_t i = 0; i < 99999; ++i) over_found = over_found || u(gen) >= 9; std::cout << std::boolalpha << over_found << std::endl; } { uniform_distribution<float> u(0, 9); bool over_found = false; for(size_t i = 0; i < 99999; ++i) over_found = over_found || u(gen) >= 9; std::cout << std::boolalpha << over_found << std::endl; } } This code illustrates that writing generic code using this class is dangerous. For example, if you'd write a generic function calculating a histogram of the results in the subranges: [0, 1), [1, 2), ..., [8, 9), the results would be incompatible.
As @revolver_ocelot points out, the standard library's [inclusive-begin, exclusive_end) convention cannot be used for uniform integers (because it would be impossible to specify a uniform integer random number generator generating also the maximum uint value), making this an exceptional signature.
5 Comments
uniform_real_distribution is not a continuous distribution over the real numbers. It's a discrete distribution over the finite subset of the rational numbers that are represented by RealType (which by default is double). Including or excluding the endpoint therefore does make a difference.[1, 1 + DBL_EPSILON) then including or not including the endpoint is the difference between the distribution being two-valued or one-valued. Anyway, if you want to take your random number and do something like 1 / (endpoint - x) to it, then you care whether there is or isn't a small probability of your code crashing. Not that the distribution of 1 / (endpoint - x) is perfect, but it's a lot worse if it sometimes divides by zero.
[rand.dist.uni.int]it states: Auniform_int_distributionrandom number distribution produces random integers i, a <= i <= b