Как произвести 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).

Другие вопросы по тегам