significa que isnan c++ double nan

que - Comprobando si un doble(o flotador) es NaN en C++



isnan c++ (20)

¿Hay una función isnan ()?

PS .: Estoy en MinGW (si eso hace una diferencia).

Resolví esto usando isnan () de <math.h> , que no existe en <cmath> , que al principio estaba <cmath> .


Primera solución: si está utilizando C ++ 11

Como se solicitó esto, hubo algunos desarrollos nuevos: es importante saber que std::isnan() es parte de C ++ 11

Sinopsis

Definido en el encabezado <cmath>

bool isnan( float arg ); (since C++11) bool isnan( double arg ); (since C++11) bool isnan( long double arg ); (since C++11)

Determina si el número de punto flotante dado arg no es un número ( NaN ).

Parámetros

arg : valor de punto flotante

Valor de retorno

true si arg es NaN , false contrario

Referencia

en.cppreference.com/w/cpp/numeric/math/isnan

Tenga en cuenta que esto es incompatible con -fast-math si usa g ++, vea más abajo para otras sugerencias.

Otras soluciones: si utiliza herramientas no compatibles con C ++ 11

Para C99, en C, esto se implementa como una macro isnan(c) que devuelve un valor int. El tipo de x será float, doble o largo doble.

Varios proveedores pueden o no incluir o no una función isnan() .

La forma supuestamente portátil de verificar si hay NaN es usar la propiedad IEEE 754 de que NaN no es igual a sí mismo: es decir, x == x será falso para que x sea NaN .

Sin embargo, es posible que la última opción no funcione con todos los compiladores y algunas configuraciones (particularmente configuraciones de optimización), por lo que, como último recurso, siempre puede verificar el patrón de bits ...


prevención de nan

Mi respuesta a esta pregunta es no usar controles retroactivos para nan . Utilice cheques preventivos para divisiones de la forma 0.0/0.0 lugar.

#include <float.h> float x=0.f ; // I''m gonna divide by x! if( !x ) // Wait! Let me check if x is 0 x = FLT_MIN ; // oh, since x was 0, i''ll just make it really small instead. float y = 0.f / x ; // whew, `nan` didn''t appear.

nan resulta de la operación 0.f/0.f , o 0.0/0.0 . nan es una némesis terrible de la estabilidad de su código que debe detectarse y prevenirse con mucho cuidado 1 . Las propiedades de nan que son diferentes de los números normales:

  • nan es tóxico, (5 * nan = nan )
  • nan no es igual a nada, ni siquiera a sí mismo ( nan ! = nan )
  • nan no mayor que nada ( nan !> 0)
  • nan no es menos que nada ( nan ! <0)

Las últimas 2 propiedades listadas son contra-lógicas y resultarán en un comportamiento impar del código que se basa en comparaciones con un número nan (la tercera última propiedad también es impar, pero probablemente nunca verás x != x ? En tu código (a menos que esté comprobando nan (poco fiable))).

En mi propio código, noté que los valores de nan tienden a producir errores difíciles de encontrar. (Tenga en cuenta que este no es el caso para inf o -inf . ( -inf <0) devuelve TRUE , (0 < inf ) devuelve TRUE, e incluso ( -inf < inf ) devuelve TRUE. Por lo tanto, en mi experiencia, el comportamiento del código es a menudo todavía como se desea).

que hacer bajo nan

Lo que quiere que ocurra bajo 0.0/0.0 debe manejarse como un caso especial , pero lo que haga debe depender de los números que espera obtener del código.

En el ejemplo anterior, el resultado de ( 0.f/FLT_MIN ) será 0 , básicamente. Es posible que desee 0.0/0.0 para generar HUGE lugar. Asi que,

float x=0.f, y=0.f, z; if( !x && !y ) // 0.f/0.f case z = FLT_MAX ; // biggest float possible else z = y/x ; // regular division.

Así que en lo anterior, si x fuera 0.f , resultaría inf (lo que en realidad tiene un comportamiento bastante bueno / no destructivo como se mencionó anteriormente).

Recuerde, la división entera por 0 provoca una excepción de tiempo de ejecución . Por lo tanto, siempre debe verificar la división de enteros entre 0. El hecho de que 0.0/0.0 evalúe en silencio a nan no significa que pueda ser perezoso y no debe verificar 0.0/0.0 antes de que suceda.

1 Las comprobaciones de nan través de x != x veces no son confiables ( x != x se elimina por algunos compiladores de optimización que -ffast-math el cumplimiento de IEEE, específicamente cuando el interruptor -ffast-math está habilitado).


A partir de C ++ 14 hay varias formas de probar si un value número de punto flotante es un NaN.

De estas formas, solo la verificación de los bits de la representación del número funciona de manera confiable, como se señaló en mi respuesta original. En particular, std::isnan y el a menudo propuesto check v != v , no funcionan de manera confiable y no deben usarse, para que su código deje de funcionar correctamente cuando alguien decida que se necesita la optimización de punto flotante, y le pide al compilador que lo haga . Esta situación puede cambiar, los compiladores pueden ser más conformes, pero para este problema no ha ocurrido en los 6 años desde la respuesta original.

Durante aproximadamente 6 años, mi respuesta original fue la solución seleccionada para esta pregunta, que estuvo bien. Sin embargo, recientemente se ha seleccionado una respuesta altamente actualizada que recomienda la prueba v != v no confiable. De ahí esta respuesta adicional más actualizada (ahora tenemos los estándares C ++ 11 y C ++ 14, y C ++ 17 en el horizonte).

Las principales formas de verificar la presencia de NaN-ness, a partir de C ++ 14, son:

  • std::isnan(value) )
    es la forma de biblioteca estándar deseada desde C ++ 11. isnan aparentemente está en conflicto con la macro Posix del mismo nombre, pero en la práctica eso no es un problema. El problema principal es que cuando se solicita la optimización aritmética de punto flotante, luego con al menos un compilador principal, a saber, g ++, std::isnan devuelve false para el argumento NaN .

  • (fpclassify(value) == FP_NAN) )
    Sufre del mismo problema que std::isnan , es decir, no es confiable.

  • (value != value) )
    Recomendado en muchas respuestas de SO. Sufre del mismo problema que std::isnan , es decir, no es confiable.

  • (value == Fp_info::quiet_NaN()) )
    Esta es una prueba que con el comportamiento estándar no debería detectar los NaN, pero que con el comportamiento optimizado podría detectar los NaN (debido a que el código optimizado simplemente compara directamente las representaciones de nivel de bits), y quizás se combine con otra forma de cubrir el comportamiento no optimizado estándar , podría detectar de forma fiable NaN. Lamentablemente resultó no funcionar de forma fiable.

  • (ilogb(value) == FP_ILOGBNAN) )
    Sufre del mismo problema que std::isnan , es decir, no es confiable.

  • isunordered(1.2345, value) )
    Sufre del mismo problema que std::isnan , es decir, no es confiable.

  • is_ieee754_nan( value ) )
    Esta no es una función estándar. Es la comprobación de los bits según el estándar IEEE 754. Es completamente confiable pero el código es algo dependiente del sistema.

En el siguiente código de prueba completo, "éxito" es si una expresión reporta Nan-ness del valor. Para la mayoría de las expresiones, esta medida de éxito, el objetivo de detectar NaN y solo NaN, corresponde a su semántica estándar. Sin embargo, para la expresión (value == Fp_info::quiet_NaN()) ) , el comportamiento estándar es que no funciona como un detector de NaN.

#include <cmath> // std::isnan, std::fpclassify #include <iostream> #include <iomanip> // std::setw #include <limits> #include <limits.h> // CHAR_BIT #include <sstream> #include <stdint.h> // uint64_t using namespace std; #define TEST( x, expr, expected ) / [&](){ / const auto value = x; / const bool result = expr; / ostringstream stream; / stream << boolalpha << #x " = " << x << ", (" #expr ") = " << result; / cout / << setw( 60 ) << stream.str() << " " / << (result == expected? "Success" : "FAILED") / << endl; / }() #define TEST_ALL_VARIABLES( expression ) / TEST( v, expression, true ); / TEST( u, expression, false ); / TEST( w, expression, false ) using Fp_info = numeric_limits<double>; inline auto is_ieee754_nan( double const x ) -> bool { static constexpr bool is_claimed_ieee754 = Fp_info::is_iec559; static constexpr int n_bits_per_byte = CHAR_BIT; using Byte = unsigned char; static_assert( is_claimed_ieee754, "!" ); static_assert( n_bits_per_byte == 8, "!" ); static_assert( sizeof( x ) == sizeof( uint64_t ), "!" ); #ifdef _MSC_VER uint64_t const bits = reinterpret_cast<uint64_t const&>( x ); #else Byte bytes[sizeof(x)]; memcpy( bytes, &x, sizeof( x ) ); uint64_t int_value; memcpy( &int_value, bytes, sizeof( x ) ); uint64_t const& bits = int_value; #endif static constexpr uint64_t sign_mask = 0x8000000000000000; static constexpr uint64_t exp_mask = 0x7FF0000000000000; static constexpr uint64_t mantissa_mask = 0x000FFFFFFFFFFFFF; (void) sign_mask; return (bits & exp_mask) == exp_mask and (bits & mantissa_mask) != 0; } auto main() -> int { double const v = Fp_info::quiet_NaN(); double const u = 3.14; double const w = Fp_info::infinity(); cout << boolalpha << left; cout << "Compiler claims IEEE 754 = " << Fp_info::is_iec559 << endl; cout << endl;; TEST_ALL_VARIABLES( std::isnan(value) ); cout << endl; TEST_ALL_VARIABLES( (fpclassify(value) == FP_NAN) ); cout << endl; TEST_ALL_VARIABLES( (value != value) ); cout << endl; TEST_ALL_VARIABLES( (value == Fp_info::quiet_NaN()) ); cout << endl; TEST_ALL_VARIABLES( (ilogb(value) == FP_ILOGBNAN) ); cout << endl; TEST_ALL_VARIABLES( isunordered(1.2345, value) ); cout << endl; TEST_ALL_VARIABLES( is_ieee754_nan( value ) ); }

Los resultados con g ++ (tenga en cuenta de nuevo que el comportamiento estándar de (value == Fp_info::quiet_NaN()) es que no funciona como detector de NaN, es de gran interés aquí):

[C:/my/forums/so/282 (detect NaN)] > g++ --version | find "++" g++ (x86_64-win32-sjlj-rev1, Built by MinGW-W64 project) 6.3.0 [C:/my/forums/so/282 (detect NaN)] > g++ foo.cpp && a Compiler claims IEEE 754 = true v = nan, (std::isnan(value)) = true Success u = 3.14, (std::isnan(value)) = false Success w = inf, (std::isnan(value)) = false Success v = nan, ((fpclassify(value) == 0x0100)) = true Success u = 3.14, ((fpclassify(value) == 0x0100)) = false Success w = inf, ((fpclassify(value) == 0x0100)) = false Success v = nan, ((value != value)) = true Success u = 3.14, ((value != value)) = false Success w = inf, ((value != value)) = false Success v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success w = inf, ((value == Fp_info::quiet_NaN())) = false Success v = nan, ((ilogb(value) == ((int)0x80000000))) = true Success u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false Success w = inf, ((ilogb(value) == ((int)0x80000000))) = false Success v = nan, (isunordered(1.2345, value)) = true Success u = 3.14, (isunordered(1.2345, value)) = false Success w = inf, (isunordered(1.2345, value)) = false Success v = nan, (is_ieee754_nan( value )) = true Success u = 3.14, (is_ieee754_nan( value )) = false Success w = inf, (is_ieee754_nan( value )) = false Success [C:/my/forums/so/282 (detect NaN)] > g++ foo.cpp -ffast-math && a Compiler claims IEEE 754 = true v = nan, (std::isnan(value)) = false FAILED u = 3.14, (std::isnan(value)) = false Success w = inf, (std::isnan(value)) = false Success v = nan, ((fpclassify(value) == 0x0100)) = false FAILED u = 3.14, ((fpclassify(value) == 0x0100)) = false Success w = inf, ((fpclassify(value) == 0x0100)) = false Success v = nan, ((value != value)) = false FAILED u = 3.14, ((value != value)) = false Success w = inf, ((value != value)) = false Success v = nan, ((value == Fp_info::quiet_NaN())) = true Success u = 3.14, ((value == Fp_info::quiet_NaN())) = true FAILED w = inf, ((value == Fp_info::quiet_NaN())) = true FAILED v = nan, ((ilogb(value) == ((int)0x80000000))) = true Success u = 3.14, ((ilogb(value) == ((int)0x80000000))) = false Success w = inf, ((ilogb(value) == ((int)0x80000000))) = false Success v = nan, (isunordered(1.2345, value)) = false FAILED u = 3.14, (isunordered(1.2345, value)) = false Success w = inf, (isunordered(1.2345, value)) = false Success v = nan, (is_ieee754_nan( value )) = true Success u = 3.14, (is_ieee754_nan( value )) = false Success w = inf, (is_ieee754_nan( value )) = false Success [C:/my/forums/so/282 (detect NaN)] > _

Resultados con Visual C ++:

[C:/my/forums/so/282 (detect NaN)] > cl /nologo- 2>&1 | find "++" Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23725 for x86 [C:/my/forums/so/282 (detect NaN)] > cl foo.cpp /Feb && b foo.cpp Compiler claims IEEE 754 = true v = nan, (std::isnan(value)) = true Success u = 3.14, (std::isnan(value)) = false Success w = inf, (std::isnan(value)) = false Success v = nan, ((fpclassify(value) == 2)) = true Success u = 3.14, ((fpclassify(value) == 2)) = false Success w = inf, ((fpclassify(value) == 2)) = false Success v = nan, ((value != value)) = true Success u = 3.14, ((value != value)) = false Success w = inf, ((value != value)) = false Success v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success w = inf, ((value == Fp_info::quiet_NaN())) = false Success v = nan, ((ilogb(value) == 0x7fffffff)) = true Success u = 3.14, ((ilogb(value) == 0x7fffffff)) = false Success w = inf, ((ilogb(value) == 0x7fffffff)) = true FAILED v = nan, (isunordered(1.2345, value)) = true Success u = 3.14, (isunordered(1.2345, value)) = false Success w = inf, (isunordered(1.2345, value)) = false Success v = nan, (is_ieee754_nan( value )) = true Success u = 3.14, (is_ieee754_nan( value )) = false Success w = inf, (is_ieee754_nan( value )) = false Success [C:/my/forums/so/282 (detect NaN)] > cl foo.cpp /Feb /fp:fast && b foo.cpp Compiler claims IEEE 754 = true v = nan, (std::isnan(value)) = true Success u = 3.14, (std::isnan(value)) = false Success w = inf, (std::isnan(value)) = false Success v = nan, ((fpclassify(value) == 2)) = true Success u = 3.14, ((fpclassify(value) == 2)) = false Success w = inf, ((fpclassify(value) == 2)) = false Success v = nan, ((value != value)) = true Success u = 3.14, ((value != value)) = false Success w = inf, ((value != value)) = false Success v = nan, ((value == Fp_info::quiet_NaN())) = false FAILED u = 3.14, ((value == Fp_info::quiet_NaN())) = false Success w = inf, ((value == Fp_info::quiet_NaN())) = false Success v = nan, ((ilogb(value) == 0x7fffffff)) = true Success u = 3.14, ((ilogb(value) == 0x7fffffff)) = false Success w = inf, ((ilogb(value) == 0x7fffffff)) = true FAILED v = nan, (isunordered(1.2345, value)) = true Success u = 3.14, (isunordered(1.2345, value)) = false Success w = inf, (isunordered(1.2345, value)) = false Success v = nan, (is_ieee754_nan( value )) = true Success u = 3.14, (is_ieee754_nan( value )) = false Success w = inf, (is_ieee754_nan( value )) = false Success [C:/my/forums/so/282 (detect NaN)] > _

Resumiendo los resultados anteriores, solo la prueba directa de la representación a nivel de bits, utilizando la is_ieee754_nanfunción definida en este programa de prueba, funcionó de manera confiable en todos los casos con g ++ y Visual C ++.

Anexo:
Después de publicar lo anterior, me di cuenta de otro posible ensayo para NaN, mencionado en otra respuesta aquí, a saber ((value < 0) == (value >= 0)). Resultó que funcionaba bien con Visual C ++ pero falló con la -ffast-mathopción de g ++ . Solo las pruebas directas de patrones de bits funcionan de manera confiable.


De acuerdo con el estándar IEEE, los valores de NaN tienen la propiedad impar de que las comparaciones que los involucran sean siempre falsas. Es decir, para un float f, f != f será verdadero solo si f es NaN.

Tenga en cuenta que, como se ha señalado en algunos comentarios a continuación, no todos los compiladores respetan esto al optimizar el código.

Para cualquier compilador que pretenda usar el punto flotante IEEE, este truco debería funcionar. Pero no puedo garantizar que funcionará en la práctica. Consulte con su compilador, en caso de duda.


El siguiente código utiliza la definición de NAN (conjunto de todos los bits de exponente, al menos un conjunto de bits fraccional) y asume que sizeof (int) = sizeof (float) = 4. Puede buscar los detalles en NAN en Wikipedia.

bool IsNan( float value ) { return ((*(UINT*)&value) & 0x7fffffff) > 0x7f800000; }


Esto funciona:

#include <iostream> #include <math.h> using namespace std; int main () { char ch=''a''; double val = nan(&ch); if(isnan(val)) cout << "isnan" << endl; return 0; }

salida: isnan


Hay tres formas "oficiales": posix isnan macro , c ++ 0x plantilla de función isnan o visual c ++ _isnan function .

Desafortunadamente, es poco práctico detectar cuál de ellos usar.

Y, desafortunadamente, no hay una manera confiable de detectar si tiene representación IEEE 754 con NaNs. La biblioteca estándar ofrece un oficial de este tipo ( numeric_limits<double>::is_iec559 ). Pero en la práctica, compiladores como g ++ estropean eso.

En teoría, uno podría usar simplemente x != x , pero los compiladores como g ++ y visual c ++ lo estropean.

Entonces, al final, pruebe los patrones de bits de NaN específicos, asumiendo (¡y con suerte, haciendo cumplir, en algún momento!) Una representación particular como IEEE 754.

EDITAR : como ejemplo de "compiladores como g ++ ... arruinar eso", considere

#include <limits> #include <assert.h> void foo( double a, double b ) { assert( a != b ); } int main() { typedef std::numeric_limits<double> Info; double const nan1 = Info::quiet_NaN(); double const nan2 = Info::quiet_NaN(); foo( nan1, nan2 ); }

Compilando con g ++ (TDM-2 mingw32) 4.4.1:

C:/test> type "C:/Program Files/@commands/gnuc.bat" @rem -finput-charset=windows-1252 @g++ -O -pedantic -std=c++98 -Wall -Wwrite-strings %* -Wno-long-long C:/test> gnuc x.cpp C:/test> a && echo works... || echo !failed works... C:/test> gnuc x.cpp --fast-math C:/test> a && echo works... || echo !failed Assertion failed: a != b, file x.cpp, line 6 This application has requested the Runtime to terminate it in an unusual way. Please contact the application''s support team for more information. !failed C:/test> _


Hay un std :: isnan si tu compilador soporta extensiones c99, pero no estoy seguro de si mingw lo hace.

Aquí hay una pequeña función que debería funcionar si su compilador no tiene la función estándar:

bool custom_isnan(double var) { volatile double d = var; return d != d; }


No hay ninguna función isnan() disponible en la biblioteca estándar de C ++ actual. Se introdujo en C99 y se definió como una macro no una función. Los elementos de la biblioteca estándar definidos por C99 no son parte de la norma actual C ++ ISO / IEC 14882: 1998 ni su actualización ISO / IEC 14882: 2003.

En 2005 se propuso el Informe Técnico 1. El TR1 trae compatibilidad con C99 a C ++. A pesar de que nunca se ha adoptado oficialmente para convertirse en estándar de C ++, muchas (las implementaciones de GCC 4.0+ o Visual C ++ 9.0+ C ++ proporcionan funciones TR1, todas ellas o solo algunas (Visual C ++ 9.0 no proporciona funciones matemáticas de C99) .

Si TR1 está disponible, entonces cmath incluye elementos C99 como isnan() , isfinite() , etc., pero se definen como funciones, no macros, generalmente en std::tr1:: namespace, aunque muchas implementaciones (es decir, GCC 4+ en Linux o en XCode en Mac OS X 10.5+) inyectarlos directamente en std:: , por lo que std::isnan está bien definido.

Además, algunas implementaciones de C ++ aún hacen que la isnan() C99 isnan() esté disponible para C ++ (incluida a través de cmath o math.h ), lo que puede causar más confusiones y los desarrolladores pueden asumir que es un comportamiento estándar.

Una nota sobre Viusal C ++, como se mencionó anteriormente, no proporciona std::isnan ni std::tr1::isnan , pero proporciona una función de extensión definida como _isnan() que ha estado disponible desde Visual C ++ 6.0

En XCode, hay aún más diversión. Como se mencionó, GCC 4+ define std::isnan . Para versiones anteriores del compilador y la biblioteca de XCode, parece (aquí hay una discusión relevante ), no he tenido la oportunidad de comprobarme a mí mismo) se definen dos funciones, __inline_isnand() en Intel y __isnand() en Power PC.


Puede usar numeric_limits<float>::quiet_NaN( ) definido en los limits la biblioteca estándar para probar. Hay una constante separada definida para el double .

#include <iostream> #include <math.h> #include <limits> using namespace std; int main( ) { cout << "The quiet NaN for type float is: " << numeric_limits<float>::quiet_NaN( ) << endl; float f_nan = numeric_limits<float>::quiet_NaN(); if( isnan(f_nan) ) { cout << "Float was Not a Number: " << f_nan << endl; } return 0; }

No sé si esto funciona en todas las plataformas, ya que solo probé con g ++ en Linux.


Puede usar la función isnan() , pero necesita incluir la biblioteca matemática de C.

#include <cmath>

Como esta función es parte de C99, no está disponible en todas partes. Si su proveedor no proporciona la función, también puede definir su propia variante de compatibilidad.

inline bool isnan(double x) { return x != x; }


También hay una biblioteca de solo encabezado presente en Boost que tiene herramientas limpias para tratar con tipos de datos de punto flotante

#include <boost/math/special_functions/fpclassify.hpp>

Obtienes las siguientes funciones:

template <class T> bool isfinite(T z); template <class T> bool isinf(T t); template <class T> bool isnan(T t); template <class T> bool isnormal(T t);

Si tiene tiempo, eche un vistazo a todo el conjunto de herramientas matemáticas de Boost, tiene muchas herramientas útiles y está creciendo rápidamente.

También cuando se trata de puntos flotantes y no flotantes, puede ser una buena idea mirar las conversiones numéricas .


Me parece que el mejor enfoque verdaderamente multiplataforma sería utilizar una unión y probar el patrón de bits del doble para comprobar si hay NaN.

No he probado a fondo esta solución, y puede haber una forma más eficiente de trabajar con los patrones de bits, pero creo que debería funcionar.

#include <stdint.h> #include <stdio.h> union NaN { uint64_t bits; double num; }; int main() { //Test if a double is NaN double d = 0.0 / 0.0; union NaN n; n.num = d; if((n.bits | 0x800FFFFFFFFFFFFF) == 0xFFFFFFFFFFFFFFFF) { printf("NaN: %f", d); } return 0; }


Teniendo en cuenta que (x! = X) no siempre se garantiza para NaN (por ejemplo, si se usa la opción -ffast-math), he estado usando:

#define IS_NAN(x) (((x) < 0) == ((x) >= 0))

Los números no pueden ser a la vez <0 y> = 0, por lo que realmente esta verificación solo se aprueba si el número no es menor que ni mayor o igual que cero. Que es básicamente ningún número, o NaN.

También puedes usar esto si prefieres:

#define IS_NAN(x) (!((x)<0) && !((x)>=0)

No estoy seguro de cómo esto se ve afectado por la matemática-rápida, por lo que su millaje puede variar.


Una posible solución que no dependería de la representación específica de IEEE para NaN utilizada sería la siguiente:

template<class T> bool isnan( T f ) { T _nan = (T)0.0/(T)0.0; return 0 == memcmp( (void*)&f, (void*)&_nan, sizeof(T) ); }


Como los comentarios anteriores indican que a! = A no funcionará en g ++ y algunos otros compiladores, pero este truco debería. Puede que no sea tan eficiente, pero sigue siendo una manera:

bool IsNan(float a) { char s[4]; sprintf(s, "%.3f", a); if (s[0]==''n'') return true; else return false; }

Básicamente, en g ++ (aunque no estoy seguro de otros), printf imprime ''nan'' en los formatos% d o% .f si la variable no es un entero / float válido. Por lo tanto, este código está comprobando que el primer carácter de la cadena sea ''n'' (como en "nan")


Después de leer las otras respuestas, quería algo que pasara a través de la advertencia de comparación de punto flotante y no se rompiera con las matemáticas rápidas. El siguiente código parece funcionar:

/* Portable warning-free NaN test: * Does not emit warning with -Wfloat-equal (does not use float comparisons) * Works with -O3 -ffast-math (floating-point optimization) * Only call to standard library is memset and memcmp via <cstring> * Works for IEEE 754 compliant floating-point representations * Also works for extended precision long double */ #include <cstring> template <class T> bool isNaN(T x) { /*Initialize all bits including those used for alignment to zero. This sets all the values to positive zero but does not clue fast math optimizations as to the value of the variables.*/ T z[4]; memset(z, 0, sizeof(z)); z[1] = -z[0]; z[2] = x; z[3] = z[0] / z[2]; /*Rationale for following test: * x is 0 or -0 --> z[2] = 0, z[3] = NaN * x is a negative or positive number --> z[3] = 0 * x is a negative or positive denormal number --> z[3] = 0 * x is negative or positive infinity --> z[3] = 0 (IEEE 754 guarantees that 0 / inf is zero) * x is a NaN --> z[3] = NaN != 0. */ //Do a bitwise comparison test for positive and negative zero. bool z2IsZero = memcmp(&z[2], &z[0], sizeof(T)) == 0 || memcmp(&z[2], &z[1], sizeof(T)) == 0; bool z3IsZero = memcmp(&z[3], &z[0], sizeof(T)) == 0 || memcmp(&z[3], &z[1], sizeof(T)) == 0; //If the input is bitwise zero or negative zero, then it is not NaN. return !z2IsZero && !z3IsZero; } //NaN test suite #include <iostream> /*If printNaN is true then only expressions that are detected as NaN print and vice versa.*/ template <class T> void test(bool printNaN) { T v[10] = {-0.0, 0.0, -1.0, 1.0, std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), std::numeric_limits<T>::denorm_min(), -std::numeric_limits<T>::denorm_min(), std::numeric_limits<T>::quiet_NaN(), std::numeric_limits<T>::signaling_NaN()}; for(int i = 0; i < 10; i++) { for(int j = 0; j < 10; j++) { if(isNaN(v[i] + v[j]) == printNaN) std::cout << v[i] << "+" << v[j] << " = " << v[i] + v[j] << std::endl; if(isNaN(v[i] - v[j]) == printNaN) std::cout << v[i] << "-" << v[j] << " = " << v[i] - v[j] << std::endl; if(isNaN(v[i] * v[j]) == printNaN) std::cout << v[i] << "*" << v[j] << " = " << v[i] * v[j] << std::endl; if(isNaN(v[i] / v[j]) == printNaN) std::cout << v[i] << "/" << v[j] << " = " << v[i] / v[j] << std::endl; } } } //Test each floating-point type. int main() { std::cout << "NaNs:" << std::endl; test<float>(true); test<double>(true); test<long double>(true); std::cout << std::endl << "Not NaNs:" << std::endl; test<float>(false); test<double>(false); test<long double>(false); return 0; }


El estándar IEEE dice que cuando el exponente es todo 1s y la mantisa no es cero, el número es un NaN. Doble es 1 bit de signo, 11 bits de exponente y 52 bits de mantisa. Hacer un poco de verificación.


En cuanto a mí, la solución podría ser una macro para hacerlo explícitamente en línea y, por lo tanto, lo suficientemente rápido. También funciona para cualquier tipo de flotador. Se basa en el hecho de que el único caso cuando un valor no es igual a sí mismo es cuando el valor no es un número.

#ifndef isnan #define isnan(a) (a != a) #endif


inline bool IsNan(float f) { const uint32 u = *(uint32*)&f; return (u&0x7F800000) == 0x7F800000 && (u&0x7FFFFF); // Both NaN and qNan. } inline bool IsNan(double d) { const uint64 u = *(uint64*)&d; return (u&0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && (u&0xFFFFFFFFFFFFFULL); }

Esto funciona si sizeof(int) es 4 y sizeof(long long) es 8.

Durante el tiempo de ejecución es solo una comparación, los castings no toman ningún tiempo. Simplemente cambia la configuración de los indicadores de comparación para verificar la igualdad.