Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will "min to max" uniform real distribution produce Inf,-Inf, or NaN?

If I were to produce floating point values in the following way:

template <typename T>
T RandomFromRange(T low, T high){
    std::random_device random_device;
    std::mt19937 engine{random_device()};
    std::uniform_real_distribution<T> dist(low, high);
    return dist(engine);
}

template <typename T>
T GetRandom(){
    return RandomFromRange
    (std::numeric_limits<T>::min(),std::numeric_limits<T>::max());
}

//produce floating point values:
auto num1 = GetRandom<float>();
auto num2 = GetRandom<float>();
auto num3 = GetRandom<float>();
//...

Is it possible that I will ever get back a NaN, Inf, or -Inf?

like image 289
Trevor Hickey Avatar asked Apr 24 '16 16:04

Trevor Hickey


2 Answers

Let's consider what std::uniform_real_distribution generates.

Produces random floating-point values i, uniformly distributed on the interval [a, b)

So, that's between std::numeric_limits<foat>::min() and std::numeric_limits<float>::max(), including former, but excluding latter. What values do those limits return? They return FLT_MIN and FLT_MAX respectively. Well, what are those?

minimum normalized positive floating-point number

maximum representable finite floating-point number

Since neither {positive,negative} infinity, nor NaN is within the range of finite numbers, no they're not generated.

As pointed out by Christopher Oicles, pay attention that FLT_MIN and by extension, std::numeric_limits<foat>::min() is the smallest positive representable value.

As pointed out by Chris Dodd, if the range of [min, max) exceeds std::numeric_limits<float>::max(), then you would get undefined behaviour and in that case any output, including generating infinity would be possible.

like image 116
eerorika Avatar answered Nov 04 '22 08:11

eerorika


Actually, this causes undefined behavior, because of the requirements for std::uniform_real_distribution (section 26.5.8.2.2 of the draft spec I have):

explicit uniform_real_distribution(RealType a = 0.0, RealType b = 1.0);
    Requires: a ≤ b and b − a ≤ numeric_limits<RealType>::max().
    Effects: Constructs a uniform_real_distribution object; a and b correspond to
             the respective parameters of the distribution.

Your specific example will overflow that numeric_limits requirement.

Now you could build a std::uniform_real_distribution<double> with std::numeric_limits<float>::min/max as the bounds, and that should be well-defined. Its also likely that your example will work on most implementations (as they generally promote floats to doubles in internal computations), but it is still hitting undefined behavior.

On implementations where it does't work, I would guess the most likely failure mode would be generating Inf, as that is what the b-a would generate.

like image 27
Chris Dodd Avatar answered Nov 04 '22 07:11

Chris Dodd