Как проверить бесконечные и неопределенные значения в C ++? - PullRequest
28 голосов
/ 04 января 2009

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

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

Indeterminate немного сложнее, потому что вы не можете сравнить неопределенное значение с некоторым другим значением. Любое сравнение возвращает ложь. Вы можете использовать это свойство для обнаружения неопределенного значения, сравнивая его с самим собой. Допустим, у вас есть двойная переменная с именем 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())
}

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

Ответы [ 6 ]

17 голосов
/ 04 января 2009

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

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

9 голосов
/ 18 июля 2013

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

C ++ 11's std::isfinite возвращает true для всех значений, кроме inf и nan; поэтому !isfinite должен проверять бесконечные и неопределенные значения в одном кадре.

3 голосов
/ 05 января 2009

Вы также можете использовать их как строгое решение 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)

3 голосов
/ 04 января 2009

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

2 голосов
/ 08 ноября 2013

Есть isfinite из C99 или POSIX или что-то, что я думаю.

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

0 голосов
/ 08 ноября 2013
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
...