Why Aren't 'Std::Uniform_Int_Distribution<Uint8_T>' and 'Std::Uniform_Int_Distribution<Int8_T>' Allowed

C++ numerics lib: std::uniform_int_distribution, change bounds of distribution between calls

What about param?

dist.param( decltype(dist)::param_type(otherMin, otherMax) );

C++11 standard (and following ones), [rand.req.dist]/9:

For each of the constructors of D taking arguments corresponding to
parameters of the distribution, P shall have a corresponding
constructor subject to the same requirements and taking arguments
identical in number, type, and default values.

Problems with uniform_int_distribution

This error is consistent with you leaving off std::, so you should use it like follows:

 std::uniform_int_distribution<> dis(0,5);

See it working live.

Note as WhozCraig mentioned you also need to include the random header:

#include <random>

bernoulli_distribution vs uniform_int_distribution

Some comments and answers suggest using uniform_real_distribution instead.

I tested uniform_real_distribution(0.0f, nextafter(1.0f, 20.f)) (to account for urd being a half-closed range) vs bernoulli_distribution and the bernoulli_distribution is faster by about 20%-25% regardless of the probability (and gave more correct results. I tested 1.0 true probability and my implementation that used the above urd values actually gave false negatives (granted one or two out of 5 one-million runs) and bernoulli gave the correct none.

So, speed-wise: bernoulli_distribution is faster than uniform_real_distribution but slower than uniform_int_distribution.

Long-story short, use the right tool for the job, don't reinvent the wheel, the STL is well-built, etc. and depending on the use-case one is better than the other.

For yes-no probability (IsPercentChance(float probability)), bernoulli_distribution is faster and better.

For pure "give me a random random bool value", uniform_int_distribution is faster and better.

Vary range of uniform_int_distribution

Distribution objects are lightweight. Simply construct a new distribution when you need a random number. I use this approach in a game engine, and, after benchmarking, it's comparable to using good old rand().

Also, I've asked how to vary the range of distribution on GoingNative 2013 live stream, and Stephen T. Lavavej, a member of the standard committee, suggested to simply create new distributions, as it shouldn't be a performance issue.

Here's how I would write your code:

using uint32 = unsigned int;

class Random {
public:
Random() = default;
Random(std::mt19937::result_type seed) : eng(seed) {}
uint32 DrawNumber(uint32 min, uint32 max);

private:
std::mt19937 eng{std::random_device{}()};
};

uint32 Random::DrawNumber(uint32 min, uint32 max)
{
return std::uniform_int_distribution<uint32>{min, max}(eng);
}

Undefined behavior (according to clang -fsanitize=integer) on libstdc++ std::random due to negative index on Mersenne Twister engine

Although as the other answer indicates it is undefined behavior per standard to instantiate std::uniform_int_distribution with uint8_t template argument, the UBsan warning here is unrelated to that.

UBSan is flagging the implementation of the Mersenne twister itself, but the implementation doesn't have any undefined behavior or bug.

If you look closely you see that the offending expression is

_M_x[__k + (__m - __n)]

where __k is a value in the range from (__n - __m) to (__n - 1) via the for loop.

All of the types involved in these operations are std::size_t which is unsigned. As a consequence these operations all use modular arithmetic and therefore even if __m - __n is negative and not representable in the unsigned type, the result of

__k + (__m - __n)

will lie between 0 and __m - 1, so that indexing the array with it is not a problem. No undefined behavior, unspecified behavior or implementation-defined behavior is involved.

The UBSan check which is flagging this is not flagging actual undefined behavior. It is perfectly ok to rely on the wrap-around behavior of unsigned arithmetic like this if one is aware of it. The unsigned overflow check is only meant to be used to flag instances of such wrap-around where it was not intentional. You shouldn't use it on other's code that might rely on it or on your own code if you might be relying on it.

In -fsanitize=address,undefined,nullability,implicit-integer-truncation,implicit-integer-arithmetic-value-change,implicit-conversion,integer all except address and undefined enable UBsan checks which are not flagging actual undefined behavior, but conditions that may be unintentional in many cases. The default -fsanitize=undefined sanitizer flag doesn't enable the unsigned integer overflow check by default for the reasons given above. See https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html for details.



Related Topics



Leave a reply



Submit