Как генерировать NaN, -Infinity и + Infinity в ANSI C?
Я использую ANSI C89 (не С++), и я хочу сгенерировать NaN, -Infinity и + Infinity.
Есть ли стандартный способ (например, стандартный макрос)?
Или существует какой-либо платформенный и независимый от компилятора способ генерации этих чисел?
float f = 0.0 / 0.0; // Is f ALWAYS in any platform is NaN?
Ответы
Ответ 1
Есть в C99, но не в предыдущих стандартах AFAIK.
В C99 у вас будут макросы NAN
и INFINITY
.
От "Математика <math.h>
" (§7.12) раздел
Макрос INFINITY расширяется до постоянного выражения типа float, представляющего положительную или неподписанную бесконечность, если доступно;...
Если вы застряли с ANSI C89, вам не повезло. См. C-FAQ 14.9.
Ответ 2
Я не знаю, является ли это стандартным или портативным, но вот старт:
[email protected]:/tmp$ cat test.c; make test; ./test
#include <stdio.h>
int main() {
printf("%f\n", 1.0 / 0);
printf("%f\n", -1.0 / 0);
printf("%f\n", 0.0 / 0);
return 0;
}
cc test.c -o test
test.c: In function ‘main’:
test.c:3: warning: division by zero
test.c:4: warning: division by zero
test.c:5: warning: division by zero
inf
-inf
-nan
Как ни странно, я не могу получить положительный NaN, используя этот наивный подход.
Также см. Это: http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html
Ответ 3
Если вы используете старый компилятор, где INFINITY
не существует, вы также можете использовать макрос HUGE_VAL
, также определенный в библиотеке <math.h>
.
HUGE_VAL
должен быть доступен в стандарте C89/C90 (ISO/IEC 9899: 1990).
Ссылки: http://en.cppreference.com/w/c/numeric/math/HUGE_VAL
Ответ 4
Существует реальный способ создания бесконечности и отрицательной бесконечности. На основе стандарта IEEE 754, которому следует C89, бесконечность определяется как число с плавающей запятой, содержащее все нули в мантиссе (первые двадцать три бита) и все единицы в показателе степени (следующие восемь битов). nan
определяется как любое число со всеми единицами в показателе степени и всем, кроме всех нулей в мантиссе (потому что эта бесконечность). Сложная часть - это генерация этого числа, но это можно сделать с помощью следующего кода:
unsigned int p = 0x7F800000; // 0xFF << 23
unsigned int n = 0xFF800000; // 0xFF8 << 20
unsigned int pnan = 0x7F800001; // or anything above this up to 0x7FFFFFFF
unsigned int nnan = 0xFF800001; // or anything above this up to 0xFFFFFFFF
float positiveInfinity = *(float *)&p;
float negativeInfinity = *(float *)&n;
float positiveNaN = *(float *)&pnan;
float negativeNaN = *(float *)&nnan;
Однако простое приведение unsigned
к float
приведет к тому, что компилятор создаст float
с тем же значением. Итак, нам нужно заставить компилятор читать память как число с плавающей запятой, что дает нам желаемый результат.