Как произвести NaN поплавок в c?
float f = (float)'a';
if(f < 0){
}
else if(f == 0){
}
else if(f > 0){
}
else{
printf("NaN\n");
}
f
не будет больше / равно / меньше 0
если это NaN
,
Но как произвести такой f
на первом месте?
Я пробовал различные способы произвести NaN
, но никто не работает..
8 ответов
Используя числа с плавающей точкой, 0.0 / 0.0
не ошибка "деление на ноль"; это приводит к NaN
,
Эта программа C печатает -nan
:
#include <stdio.h>
int main()
{
float x = 0.0 / 0.0;
printf("%f\n", x);
return 0;
}
С точки зрения того, что NaN
Похоже на компьютер, два "недопустимых" числа зарезервированы для "сигнализации" и "тихого" NaN (аналогично двум недопустимым номерам, зарезервированным для положительной и отрицательной бесконечности). Запись в Википедии содержит более подробную информацию о том, как NaN представляется в виде числа с плавающей точкой IEE.
Чтобы получить нан, есть несколько способов:
1) создать его вручную (читать ieee754
правильно установить биты)
2) использовать макрос. GCC выставляет макрос NAN
, Это определено в математике
Общий способ проверить на нан - это проверить if (f == f)
(который должен потерпеть неудачу для значений nan)
Для nan все показательные биты в представлении с плавающей точкой должны быть равны 1 (число с плавающей запятой состоит из подписанного бита, набора экспонентных битов и набора битов мантиссы).
Вы можете использовать NAN
макрос или просто один из nan/nanf
функции для присвоения значения nan переменной.
чтобы проверить, имеете ли вы дело со значением nan, вы можете использовать isnan()
, Вот пример:
#include <stdio.h>
#include <math.h>
int main(void) {
float a = NAN;//using the macro in math.h
float f = nanf("");//using the function version
double d = nan("");//same as above but for doubles!
printf("a = %f\nf = %f\nd = %f\n",a,f,d);
if(isnan(a))
puts("a is a not a number!(NAN)\n");
return 0;
}
Запуск приведенного выше фрагмента кода даст вам такой вывод:
a = nan
f = nan
d = nan
a is a not a number!(NAN)
Запустите код самостоятельно: http://ideone.com/WWZBl8
читать больше информации: http://www.cplusplus.com/reference/cmath/NAN/
Для размещенных реализаций C можно сделать #include <math.h>
и использовать NAN
макрос, если определен. Например, с GCC это реализуется встроенным: (__builtin_nanf (""))
,
Для автономных реализаций C (на которых <math.h>
заголовок может быть недоступен) или когда NAN
макрос не определен (что может произойти, даже если могут поддерживаться NaN), можно создать NaN с помощью операции с плавающей запятой, такой как 0.0 / 0.0
, Тем не менее, может быть несколько проблем с этим.
Во-первых, такая операция также генерирует исключение с возможной ловушкой для некоторых реализаций Си. Можно убедиться, что он вычисляется во время компиляции с помощью:
static double my_nan = 0.0 / 0.0;
Другая проблема заключается в том, что Microsoft Visual C++ (по крайней мере, некоторые версии) пытается оценить 0.0 / 0.0
во время компиляции (даже когда это выражение находится в произвольном месте в коде) и жалуется на его достоверность. Итак, решение здесь противоположное: убедитесь, что компилятор не оценит его во время компиляции, выполнив:
static double zero = 0.0;
а затем использовать zero / zero
, Поскольку эти решения противоречат друг другу, можно протестировать компилятор с помощью директив препроцессора (#if
...) на определенных макросах.
Можно также выбрать решение, основанное на кодировании NaN, но есть и проблемы с переносимостью. Во-первых, стандарт IEEE 754 не полностью определяет кодирование NaN, в частности, способ различать тихие и сигнальные NaN (и аппаратные средства отличаются на практике); сигнальные NaNs приведут к неопределенному поведению. Кроме того, стандарт IEEE 754 не определяет, как битовая строка представляется в памяти, то есть может потребоваться обнаружение порядка байтов. Если эти проблемы решены, объединение или массив unsigned char
с приведением указателя можно получить тип с плавающей точкой. Не используйте целое число с указателем, приведенным к его адресу, чтобы делать типизацию, так как это нарушит правила псевдонимов Си.
Из руководства GNU GCC math.h
определяет макросы, которые позволяют вам явно установить переменную в бесконечность или NaN. Так как это часть C99, я надеюсь, что вы можете использовать следующие макросы с другими c99-совместимыми компиляторами.
- Macro: float INFINITY Выражение, представляющее положительную бесконечность. Он равен значению, получаемому математическими операциями, такими как 1,0 / 0,0. -INFINITY представляет отрицательную бесконечность.
Вы можете проверить, является ли значение с плавающей точкой бесконечным, сравнив его с этим макросом. Однако это не рекомендуется; вы должны использовать вместо этого isfinite макрос. Смотрите классы с плавающей точкой.
Этот макрос был введен в стандарт ISO C99.
- Macro: float NAN Выражение, представляющее значение, которое "не число". Этот макрос является расширением GNU, доступным только на машинах, которые поддерживают значение "не число", то есть на всех машинах, которые поддерживают IEEE с плавающей запятой.
Вы можете использовать '#ifdef NAN', чтобы проверить, поддерживает ли машина NaN. (Конечно, вы должны сделать так, чтобы расширения GNU были видимыми, например, путем определения _GNU_SOURCE, а затем вы должны включить math.h.)
Для получения дополнительной информации вы можете увидеть здесь: http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html
А -nan
также можно создать, установив все 32 бита переменной с плавающей запятой как 1, как показано ниже:
float nan_val = 0xffffffff;
Кроме того, вы можете сравнить, является ли переменная с плавающей запятой -nan
явно путем проверки того, не удается ли сравнение с самим собой.
if (nan_val != nan_val) {
// executes iff nan_val is -nan
}
Этот метод сравнения должен работать для компиляторов, использующих числа с плавающей запятой IEEE.
Это работает и для констант (0/0 приведет к ошибке компиляции на vs):
const unsigned maxU = ~0;
const float qNan = *((float*)&maxU);
Следующая программа на C выдаст NaN. Второе утверждение приведет к NaN.
#include <stdio.h>
#include <tchar.h>
#include "math.h"
int _tmain(int argc, _TCHAR* argv[])
{
double dSQRTValue = sqrt( -1.00 );
double dResult = -dSQRTValue; // This statement will result in a NaN.
printf( "\n %lf", dResult );
return 0;
}
Ниже будет вывод программы.
1. # QNAN0
nan генерируется, когда мы программируем, содержат значение, такое как 0.0/0.0, как сказано @Dan Cecile OR sqrt(-1).