Если бы я производил значения с плавающей точкой следующим образом:
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>();
//...
Возможно ли, что я когда-нибудь вернусь NaN
, Inf
, или же -Inf
?
Давайте посмотрим, что std::uniform_real_distribution
генерирует.
Создает случайные значения с плавающей точкой i, равномерно распределенные по интервалу [a, b)
Итак, это между std::numeric_limits<foat>::min()
а также std::numeric_limits<float>::max()
, включая первое, но исключая второе. Какие значения возвращают эти ограничения? Они вернулись FLT_MIN
а также FLT_MAX
соответственно. Ну что это?
нормализованный минимум положительный число с плавающей точкой
максимальное представимое конечное число с плавающей точкой
Поскольку ни {положительная, отрицательная} бесконечность, ни NaN не находятся в диапазоне конечных чисел, они не генерируются.
Как отметил Кристофер Оиклз, обратите внимание, что FLT_MIN
и, соответственно, std::numeric_limits<foat>::min()
самый маленький положительный представительная ценность.
Как указал Крис Додд, если диапазон [min, max)
превышает std::numeric_limits<float>::max()
, тогда вы получите неопределенное поведение, и в этом случае будет возможен любой вывод, включая генерацию бесконечности.
На самом деле, это вызывает неопределенное поведение, из-за требований к std::uniform_real_distribution
(раздел 26.5.8.2.2 проекта спецификации у меня есть):
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.
Ваш конкретный пример будет переполнен, что numeric_limits
требование.
Теперь ваша очередь мог построить std::uniform_real_distribution<double>
с std::numeric_limits<float>::min
/max
как границы, и это должно быть четко определено. Также вероятно, что ваш пример будет работать на большинстве реализаций (так как они обычно продвигают числа с плавающей запятой во внутренних вычислениях), но он все еще поражает неопределенное поведение.
На реализациях, где это не работает, я бы предположил, что наиболее вероятный режим отказа будет генерировать Inf
, как это то, что b-a
будет генерировать.