Как использовать nan и inf в C?
У меня есть численный метод, который может вернуть nan или inf, если была ошибка, и для тестирования я хотел бы временно заставить его вернуть nan или inf, чтобы убедиться, что ситуация обрабатывается правильно. Есть ли надежный,компилятор-независимая способ создания значений nan и inf в C?
после поиска в Google в течение примерно 10 минут я смог найти только зависимые от компилятора решения.
8 ответов:
вы можете проверить, если ваша реализация это:
#include <math.h> #ifdef NAN /* NAN is supported */ #endif #ifdef INFINITY /* INFINITY is supported */ #endifсуществование
INFINITYгарантируется C99( или, по крайней мере, последним черновиком) и " расширяется до постоянного выражения типа float, представляющего положительное или беззнаковое бесконечность, если она доступна; иначе к положительной константе типа float, которая переполняется во время перевода."
NANможет или не может быть определено, и " определяется тогда и только тогда, когда реализация поддерживает тихие NaNs для типа float. Он расширяется до постоянного выражения типа float, представляющего собой Тихий NaN."обратите внимание, что если вы сравниваете значения с плавающей запятой, и сделать:
a = NAN;даже тогда,
a == NAN;ложно. Один из способов проверить НАН будет:
#include <math.h> if (isnan(a)) { ... }вы также можете сделать:
a != aчтобы проверить, еслиaНэн.есть еще
isfinite(),isinf(),isnormal()иsignbit()макросы вmath.hв C99.C99 также имеет
nanфункции:#include <math.h> double nan(const char *tagp); float nanf(const char *tagp); long double nanl(const char *tagp);(ссылка: n1256).
нет независимого от компилятора способа сделать это, поскольку ни стандарты C (ни c++) не говорят, что математические типы с плавающей запятой должны поддерживать NAN или INF.
Edit: Я только что проверил формулировку стандарта C++, и он говорит, что эти функции (члены шаблонного класса numeric_limits):
quiet_NaN() signalling_NaN()будет осуществляться возврат НЭН представлений "при наличии". Он не распространяется на то, что означает "если доступно", но предположительно что-то вроде "если реализация FP rep поддерживает их". Аналогично существует функция:
infinity()который возвращает положительный INF rep "если доступно".
Они оба определены в
<limits>заголовок-я бы предположил, что стандарт C имеет что-то подобное (вероятно, также "если доступно"), но у меня нет копии текущего стандарта C99.
независимый от компилятора способ, но не независимый от процессора способ получить эти:
int inf = 0x7F800000; return *(float*)&inf; int nan = 0x7F800001; return *(float*)&nan;Это должно работать на любом процессоре, который использует формат IEEE 754 с плавающей запятой (что x86 делает).
обновление: протестировано и обновлено.
это работает для обоих
floatиdouble:double NAN = 0.0/0.0; double POS_INF = 1.0 /0.0; double NEG_INF = -1.0/0.0;изменить: Как кто-то уже сказал, старый стандарт IEEE сказал, что такие значения должны вызывать ловушки. Но новые компиляторы почти всегда выключайте ловушки и возвращайте заданные значения, потому что захват препятствует ошибке обращение.
<inf.h> /* IEEE positive infinity. */ #if __GNUC_PREREQ(3,3) # define INFINITY (__builtin_inff()) #else # define INFINITY HUGE_VALF #endifи
<bits/nan.h> #ifndef _MATH_H # error "Never use <bits/nan.h> directly; include <math.h> instead." #endif /* IEEE Not A Number. */ #if __GNUC_PREREQ(3,3) # define NAN (__builtin_nanf ("")) #elif defined __GNUC__ # define NAN \ (__extension__ \ ((union { unsigned __l __attribute__ ((__mode__ (__SI__))); float __d; }) \ { __l: 0x7fc00000UL }).__d) #else # include <endian.h> # if __BYTE_ORDER == __BIG_ENDIAN # define __nan_bytes { 0x7f, 0xc0, 0, 0 } # endif # if __BYTE_ORDER == __LITTLE_ENDIAN # define __nan_bytes { 0, 0, 0xc0, 0x7f } # endif static union { unsigned char __c[4]; float __d; } __nan_union __attribute_used__ = { __nan_bytes }; # define NAN (__nan_union.__d) #endif /* GCC. */
Я также удивлен, что это не константы времени компиляции. Но я полагаю, что вы могли бы создать эти значения достаточно легко, просто выполнив инструкцию, которая возвращает такой недопустимый результат. Деление на 0, лог 0, Тан 90, что-то вроде этого.
Я обычно использую
#define INFINITY (1e999)или
const double INFINITY = 1e999который работает по крайней мере в контекстах IEEE 754, потому что самое высокое представимое двойное значение примерно
1e308.1e309будет работать так же хорошо, как бы1e99999, но три девятки достаточно и запоминающимся. Так как это либо двойной литерал (в#defineслучае) илиInfзначение, оно останется бесконечным, даже если вы используете 128-битные ("длинные двойные") поплавки.
Comments