Как вы проверяете наличие бесконечных и неопределенных значений в C ++?
-
03-07-2019 - |
Вопрос
В моих программах бесконечность обычно возникает, когда значение делится на ноль.Я получаю неопределенное значение, когда делю ноль на ноль.Как вы проверяете наличие бесконечных и неопределенных значений в 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