Как вы проверяете наличие бесконечных и неопределенных значений в C ++?

StackOverflow https://stackoverflow.com/questions/410853

Вопрос

В моих программах бесконечность обычно возникает, когда значение делится на ноль.Я получаю неопределенное значение, когда делю ноль на ноль.Как вы проверяете наличие бесконечных и неопределенных значений в C ++?

В C ++ бесконечность представлена символом 1.#INF.Неопределенное значение представлено значением -1.#IND.Проблема в том, как проверить, является ли переменная бесконечной или неопределенной.Проверка бесконечности относительно проста:Вы найдете определение бесконечности в вашем конкретном C ++.В моем случае (VS2003) это std::numeric_limits::infinity().Вы должны включить "ограничения", чтобы использовать его.Вы можете присвоить это бесконечное значение переменной и сравнить его с некоторым значением, чтобы проверить, является ли это значение бесконечным.

Неопределенное значение немного сложнее, потому что вы не можете сравнить неопределенное значение с каким-либо другим значением.Любое сравнение возвращает значение false.Вы можете использовать это свойство для определения неопределенного значения путем сравнения его с самим собой.Допустим, у вас есть двойная переменная с именем aVal .При нормальных условиях aVal != aVal возвращает false.Но если значение не определено, aIndVal != aIndVal возвращает true.Эта странная ситуация отсутствует для бесконечных значений, т.е.aInfVal != aInfVal всегда возвращает false.

Вот две функции, которые можно использовать для проверки наличия неопределенных и бесконечных значений:

#include "limits.h"
#include "math.h"

bool isIndeterminate(const double pV)
{
    return (pV != pV);
} 

bool isInfinite(const double pV)
{
    return (fabs(pV) == std::numeric_limits::infinity())
}

Есть ли лучшие способы для этих проверок, я что-нибудь упускаю?

Это было полезно?

Решение

Для Visual Studio я бы использовал _isnan и _finite, или , возможно , _fpclass.

Но если у вас есть доступ к стандартной библиотеке и компилятору с поддержкой C ++ 11, вы могли бы использовать std::isnan и std::isinf.

Другие советы

Хотя C ++ 03 не предоставляет C99 иснан и isinf макросы, C ++ 11 стандартизирует их, предоставляя в виде функции.Если вы можете использовать C ++ 11 вместо строгого C ++ 03, то это были бы более чистые варианты, позволяющие избежать макросов, встроенные модули компилятора и зависящие от платформы функции.

C ++ 11-х годов std::isfinite ВОЗВРАТ true для всех значений, кроме inf и nan;итак !isfinite следует проверять наличие бесконечных и неопределенных значений за один раз.

Хотя это и не является строго частью C ++ 03, если ваш компилятор предоставляет некоторые из новых функций стандартного файла заголовка C99 <math.h> , у вас может быть доступ к следующим "функциональным макросам": isfinite, isinf, isnan.Если это так, то это был бы самый простой и безопасный способ выполнить эти проверки.

Вы также можете использовать их как строгое решение только для C ++.На самом деле они предлагают не больше, чем решение OP, за исключением дополнительной безопасности за счет использования характеристик типа и, возможно, незначительного увеличения скорости в случае is_inf.

template <bool> struct static_assert;
template <> struct static_assert<true> { };

template<typename T>
inline bool is_NaN(T const& x) {
    static_cast<void>(sizeof(static_assert<std::numeric_limits<T>::has_quiet_NaN>));
    return std::numeric_limits<T>::has_quiet_NaN and (x != x);
}

template <typename T>
inline bool is_inf(T const& x) {
    static_cast<void>(sizeof(static_assert<std::numeric_limits<T>::has_infinity>));
    return x == std::numeric_limits<T>::infinity() or x == -std::numeric_limits<T>::infinity();
}

(остерегайтесь самодельных static_assert)

Там есть isfinite из C99, или POSIX, или что-то в этом роде, я думаю.

Один из хакерских способов сделать это - протестировать x-x == 0;если x бесконечно или NaN, тогда x-x является ли NaN таким образом, что сравнение завершается неудачей, в то время как если x является конечным, тогда x-x является 0 и сравнение получается удачным.Я бы рекомендовал использовать isfinite, однако, или упаковать этот тест в функцию / макрос, называемый чем-то вроде isfinite так что вы сможете избавиться от всего этого, когда придет время.

if (x!=x)              ... then x is nan
if (x>0 && x/x != x/x) ... then x is +inf
if (x<0 && x/x != x/x) ... then x is -inf

это также может сработать (но включает вызов exp() и проверку равенства удвоений):

if (exp(-x)==0.) ... then x is inf
if (exp(x)==0.)  ... then x is -inf
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top