6

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?

Trevor Hickey
  • 36,288
  • 32
  • 162
  • 271

2 Answers2

10

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.

Community
  • 1
  • 1
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • 1
    For floating-point types, `std::numeric_limits::min()` is a positive value (the smallest nonzero positive value). And the difference: `std::numeric_limits::max() - std::numeric_limits::min()` usually ends up equal to `std::numeric_limits::max()` (certainly not greater, in any case). So I'm not sure if Trevor knew about this or not, but his range choice did manage to avoid undefined behavior from the distribution. – Christopher Oicles Apr 25 '16 at 01:56
  • @ChristopherOicles good point, I hadn't realized that. I've incorporated that in my answer. – eerorika Apr 25 '16 at 08:13
6

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.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226