Как произвести NaN поплавок в c? - PullRequest
18 голосов
/ 27 августа 2011
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 ]

19 голосов
/ 27 августа 2011

Чтобы произвести нан, есть несколько способов:

1) сгенерируйте его вручную (прочитайте ieee754, чтобы правильно установить биты)

2) использовать макрос. GCC выставляет макрос NAN. Это определено в math.h

Общий способ проверки для nan - это проверка if (f == f) (который должен потерпеть неудачу для значений nan)

Для nan все показательные биты в представлении с плавающей запятой должны быть установлены в 1 (float состоит из подписанного бита, набора показательных битов и набора битов мантиссы)

18 голосов
/ 27 августа 2011

При использовании чисел с плавающей запятой 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.

4 голосов
/ 15 октября 2015

Вы можете использовать макрос NAN или просто одну из nan/nanf функций, чтобы присвоить значение 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/

3 голосов
/ 19 апреля 2017

Для размещенных реализаций 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 с приведением указателя вполне подходят для получения типа с плавающей точкой.Не используйте целое число с указателем, приведенным к его адресу, чтобы делать типизацию, так как это нарушит правила псевдонимов C.

3 голосов
/ 27 августа 2011

Из руководства GNU GCC math.h определяет макросы, которые позволяют вам явно установить переменную в бесконечность или NaN. Так как это часть C99, вы можете использовать следующие макросы с другими c99-совместимыми компиляторами, я надеюсь.

- Макрос: float INFINITY Выражение, представляющее положительную бесконечность. Он равен значению, получаемому математическими операциями, такими как 1,0 / 0,0. -INFINITY представляет отрицательную бесконечность.

Вы можете проверить, является ли значение с плавающей точкой бесконечным, сравнив его с этим макросом. Однако это не рекомендуется; вместо этого вы должны использовать макрос isfinite. См. Классы с плавающей точкой.

Этот макрос был введен в стандарт ISO C99.

- Макрос: float NAN Выражение, представляющее значение, которое является «не числом». Этот макрос является расширением GNU, доступным только на машинах, которые поддерживают значение «не число», то есть на всех машинах, которые поддерживают IEEE с плавающей запятой.

Вы можете использовать "#ifdef NAN", чтобы проверить, поддерживает ли машина NaN. (Конечно, вы должны сделать так, чтобы расширения GNU были видны, например, определив _GNU_SOURCE, а затем вы должны включить math.h.)

для получения дополнительной информации вы можете увидеть здесь: http://www.gnu.org/s/hello/manual/libc/Infinity-and-NaN.html

1 голос
/ 13 июня 2013

Это работает и для констант (0/0 приведет к ошибке компиляции на vs):

const unsigned maxU = ~0;
const float qNan =  *((float*)&maxU);
0 голосов
/ 14 февраля 2016

nan получается, когда мы программируем, содержат значение, такое как 0.0 / 0.0, как сказано @Dan Cecile ИЛИ sqrt (-1).

0 голосов
/ 06 октября 2014

Следующая программа на 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

...