Comprobando si un doble (o float) es NaN en C ++

¿Hay una función de isnan ()?

PD .: Estoy en MinGW (si eso hace la diferencia).

Esto se solucionó usando isnan () de , que no existe en , que estaba #include al principio.

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

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

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

No hay 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 forman parte del estándar actual de C ++ ISO / IEC 14882: 1998 ni su actualización ISO / IEC 14882: 2003.

En 2005, se propuso el Informe técnico 1. El TR1 brinda compatibilidad con C99 a C ++. A pesar del hecho de que nunca se ha adoptado oficialmente para convertirse en estándar C ++, muchas implementaciones 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 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 hay muchas implementaciones (es decir, GCC 4+ en Linux o en XCode en Mac OS X 10.5+) inyéctelos directamente a std:: , entonces 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 las versiones anteriores del comstackdor y la biblioteca forman XCode, parece (aquí hay discusión relevante ), no he tenido la oportunidad de verificarme a mí mismo), se definen dos funciones, __inline_isnand() en Intel y __isnand() en Power PC.

Primera solución: si estás usando C ++ 11

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

Sinopsis

Definido en el encabezado

 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

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

Tenga en cuenta que esto es incompatible con -matemáticas rápidas si usa g ++, consulte a continuación otras sugerencias.


Otras soluciones: si usa herramientas que no cumplen con C ++ 11

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

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

La forma supuestamente portátil de verificar 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, la última opción puede no funcionar con todos los comstackdores y algunas configuraciones (particularmente las configuraciones de optimización), así que en última instancia, siempre puedes verificar el patrón de bits …

También hay una biblioteca de solo cabecera presente en Boost que tiene herramientas claras para tratar con tipos de datos de coma flotante

 #include  

Obtienes las siguientes funciones:

 template  bool isfinite(T z); template  bool isinf(T t); template  bool isnan(T t); template  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.

Además, cuando se trata de puntos flotantes y no flotantes, puede ser una buena idea mirar las Conversiones Numéricas .

Hay tres formas “oficiales”: posix isnan macro , c ++ 0x isnan function template , o visual c ++ _isnan function .

Lamentablemente, no es práctico detectar cuál de esos usar.

Y desafortunadamente, no hay una forma confiable de detectar si tiene representación IEEE 754 con NaN. La biblioteca estándar ofrece una forma oficial de este tipo ( numeric_limits::is_iec559 ). Pero en la práctica comstackdores como g ++ lo arruinan.

En teoría, uno podría usar simplemente x != x , pero los comstackdores como g ++ y Visual C ++ lo arruinan.

Así que, al final, prueba los patrones de bit de NaN específicos, asumiendo (y con suerte aplicando, en algún momento) una representación particular como IEEE 754.


EDITAR : como un ejemplo de “comstackdores como g ++ … arruina eso”, considera

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

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

 C: \ test> escribe "C: \ Archivos de progtwig \ @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 funciona ... ||  echo! fallido
 trabajos...

 C: \ test> gnuc x.cpp --fast-math

 C: \ test> a && echo funciona ... ||  echo! fallido
 La aserción falló: a! = B, archivo x.cpp, línea 6

 Esta aplicación ha solicitado que Runtime lo rescinda de forma inusual.
 Por favor, póngase en contacto con el equipo de soporte de la aplicación para obtener más información.
 !ha fallado

 C: \ prueba> _

Hay un std :: isnan si el comstackdor admite extensiones c99, pero no estoy seguro si mingw lo hace.

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

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

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

 #include  #include  #include  using namespace std; int main( ) { cout << "The quiet NaN for type float is: " << numeric_limits::quiet_NaN( ) << endl; float f_nan = numeric_limits::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 debe incluir la biblioteca matemática C.

 #include  

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 para compatibilidad.

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

nan prevención

Mi respuesta a esta pregunta es que no use verificaciones retroactivas para nan . Use controles preventivos para las divisiones del formulario 0.0/0.0 lugar.

 #include  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 nemesis terrible para 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 es más que nada ( nan !> 0)
  • nan no es menos que nada ( nan ! <0)

Las últimas 2 propiedades enumeradas son contra-lógicas y darán como resultado un comportamiento extraño del código que se basa en comparaciones con un número nan (la tercera propiedad es impar también, pero probablemente nunca verás x != x ? código (a menos que esté buscando nan (no confiable))).

En mi propio código, noté que los valores 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. Entonces, en mi experiencia, el comportamiento del código a menudo sigue siendo el deseado).

que hacer bajo nan

Lo que quiere que suceda por debajo de 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. Puede 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. 

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

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

1 Las comprobaciones de nan vía x != x veces no son confiables ( x != x siendo eliminado por algunos comstackdores de optimización que rompen el cumplimiento de IEEE, específicamente cuando el -ffast-math está habilitado).

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

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

 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, las fundiciones no toman tiempo. Simplemente cambia la configuración de indicadores de comparación para verificar la igualdad.

A partir de C ++ 14 hay varias maneras de probar si un value numérico de coma flotante es un NaN.

De estas maneras, solo la comprobación de los bits de la representación del número funciona de manera confiable, como se indica en mi respuesta original. En particular, std::isnan y la comprobación a menudo propuesta v != v , no funcionan de manera confiable y no deberían usarse, para que el código deje de funcionar correctamente cuando alguien decide que se necesita la optimización de coma flotante, y le pide al comstackdor que haga eso . Esta situación puede cambiar, los comstackdores pueden obtener más conformidad, pero para este problema eso no ha sucedido 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 estaba bien. Pero recientemente se ha seleccionado una respuesta altamente recomendada 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 el NaN-ness, a partir de C ++ 14, son:

  • std::isnan(value) )
    es la biblioteca estándar prevista desde C ++ 11. isnan aparentemente entra en conflicto con la macro Posix del mismo nombre, pero en la práctica eso no es un problema. El principal problema es que cuando se solicita la optimización aritmética de punto flotante, entonces con al menos un comstackdor principal, es decir, 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 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 NaNs, pero que con el comportamiento optimizado podría detectar NaNs (debido a código optimizado simplemente comparando las representaciones de nivel de bits directamente), y quizás combinarse con otra forma de cubrir el comportamiento estándar no optimizado , podría detectar NaN de manera confiable. Lamentablemente, resultó no funcionar de manera confiable.

  • (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. Está comprobando los bits de acuerdo con el estándar IEEE 754. Es completamente confiable pero el código es de alguna manera dependiente del sistema.


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

 #include  // std::isnan, std::fpclassify #include  #include  // std::setw #include  #include  // CHAR_BIT #include  #include  // 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; 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( 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 ) ); } 

Resultados con g ++ (observe nuevamente que el comportamiento estándar de (value == Fp_info::quiet_NaN()) es que no funciona como un detector de NaN, aquí tiene mucho interés práctico):

 [C: \ my \ forums \ so \ 282 (detectar NaN)]
 > g ++ --version |  encontrar "++"
 g ++ (x86_64-win32-sjlj-rev1, construido por el proyecto MinGW-W64) 6.3.0

 [C: \ my \ forums \ so \ 282 (detectar NaN)]
 > g ++ foo.cpp && a
 El comstackdor afirma que IEEE 754 = verdadero

 v = nan, (std :: isnan (value)) = true Éxito
 u = 3.14, (std :: isnan (value)) = falso Éxito
 w = inf, (std :: isnan (value)) = falso Éxito

 v = nan, ((fpclassify (value) == 0x0100)) = true Éxito
 u = 3.14, ((fpclassify (value) == 0x0100)) = falso Éxito
 w = inf, ((fpclassify (value) == 0x0100)) = falso Éxito

 v = nan, ((value! = value)) = true Éxito
 u = 3.14, ((valor! = valor)) = falso Éxito
 w = inf, ((valor! = valor)) = falso Éxito

 v = nan, ((value == Fp_info :: quiet_NaN ())) = falso FAILED
 u = 3.14, ((valor == Fp_info :: quiet_NaN ())) = falso Éxito
 w = inf, ((valor == Fp_info :: quiet_NaN ())) = falso Éxito

 v = nan, ((ilogb (value) == ((int) 0x80000000))) = true Éxito
 u = 3.14, ((ilogb (valor) == ((int) 0x80000000))) = falso Éxito
 w = inf, ((ilogb (valor) == ((int) 0x80000000))) = falso Éxito

 v = nan, (isunordered (1.2345, value)) = true Éxito
 u = 3.14, (no está ordenado (1.2345, valor)) = falso Éxito
 w = inf, (no solicitado (1.2345, valor)) = falso Éxito

 v = nan, (is_ieee754_nan (value)) = true Éxito
 u = 3.14, (is_ieee754_nan (value)) = falso Éxito
 w = inf, (is_ieee754_nan (value)) = falso Éxito

 [C: \ my \ forums \ so \ 282 (detectar NaN)]
 > g ++ foo.cpp -ffast-math && a
 El comstackdor afirma que IEEE 754 = verdadero

 v = nan, (std :: isnan (value)) = false FALLO
 u = 3.14, (std :: isnan (value)) = falso Éxito
 w = inf, (std :: isnan (value)) = falso Éxito

 v = nan, ((fpclassify (value) == 0x0100)) = FAILED
 u = 3.14, ((fpclassify (value) == 0x0100)) = falso Éxito
 w = inf, ((fpclassify (value) == 0x0100)) = falso Éxito

 v = nan, ((value! = value)) = false FAILED
 u = 3.14, ((valor! = valor)) = falso Éxito
 w = inf, ((valor! = valor)) = falso Éxito

 v = nan, ((value == Fp_info :: quiet_NaN ())) = true Éxito
 u = 3.14, ((valor == Fp_info :: quiet_NaN ())) = verdadero FALLA
 w = inf, ((value == Fp_info :: quiet_NaN ())) = true FAILED

 v = nan, ((ilogb (value) == ((int) 0x80000000))) = true Éxito
 u = 3.14, ((ilogb (valor) == ((int) 0x80000000))) = falso Éxito
 w = inf, ((ilogb (valor) == ((int) 0x80000000))) = falso Éxito

 v = nan, (isunordered (1.2345, value)) = falso FAILED
 u = 3.14, (no está ordenado (1.2345, valor)) = falso Éxito
 w = inf, (no solicitado (1.2345, valor)) = falso Éxito

 v = nan, (is_ieee754_nan (value)) = true Éxito
 u = 3.14, (is_ieee754_nan (value)) = falso Éxito
 w = inf, (is_ieee754_nan (value)) = falso Éxito

 [C: \ my \ forums \ so \ 282 (detectar NaN)]
 > _

Resultados con Visual C ++:

 [C: \ my \ forums \ so \ 282 (detectar NaN)]
 > cl / nologo- 2> & 1 |  encontrar "++"
 Microsoft (R) C / C ++ Optimizing Compiler versión 19.00.23725 para x86

 [C: \ my \ forums \ so \ 282 (detectar NaN)]
 > cl foo.cpp / Feb && b
 foo.cpp
 El comstackdor afirma que IEEE 754 = verdadero

 v = nan, (std :: isnan (value)) = true Éxito
 u = 3.14, (std :: isnan (value)) = falso Éxito
 w = inf, (std :: isnan (value)) = falso Éxito

 v = nan, ((fpclassify (value) == 2)) = true Éxito
 u = 3.14, ((fpclassify (value) == 2)) = falso Éxito
 w = inf, ((fpclassify (value) == 2)) = falso Éxito

 v = nan, ((value! = value)) = true Éxito
 u = 3.14, ((valor! = valor)) = falso Éxito
 w = inf, ((valor! = valor)) = falso Éxito

 v = nan, ((value == Fp_info :: quiet_NaN ())) = falso FAILED
 u = 3.14, ((valor == Fp_info :: quiet_NaN ())) = falso Éxito
 w = inf, ((valor == Fp_info :: quiet_NaN ())) = falso Éxito

 v = nan, ((ilogb (value) == 0x7fffffff)) = true Éxito
 u = 3.14, ((ilogb (valor) == 0x7fffffff)) = falso Éxito
 w = inf, ((ilogb (value) == 0x7fffffff)) = true FAILED

 v = nan, (isunordered (1.2345, value)) = true Éxito
 u = 3.14, (no está ordenado (1.2345, valor)) = falso Éxito
 w = inf, (no solicitado (1.2345, valor)) = falso Éxito

 v = nan, (is_ieee754_nan (value)) = true Éxito
 u = 3.14, (is_ieee754_nan (value)) = falso Éxito
 w = inf, (is_ieee754_nan (value)) = falso Éxito

 [C: \ my \ forums \ so \ 282 (detectar NaN)]
 > cl foo.cpp / Feb / fp: rápido && b
 foo.cpp
 El comstackdor afirma que IEEE 754 = verdadero

 v = nan, (std :: isnan (value)) = true Éxito
 u = 3.14, (std :: isnan (value)) = falso Éxito
 w = inf, (std :: isnan (value)) = falso Éxito

 v = nan, ((fpclassify (value) == 2)) = true Éxito
 u = 3.14, ((fpclassify (value) == 2)) = falso Éxito
 w = inf, ((fpclassify (value) == 2)) = falso Éxito

 v = nan, ((value! = value)) = true Éxito
 u = 3.14, ((valor! = valor)) = falso Éxito
 w = inf, ((valor! = valor)) = falso Éxito

 v = nan, ((value == Fp_info :: quiet_NaN ())) = falso FAILED
 u = 3.14, ((valor == Fp_info :: quiet_NaN ())) = falso Éxito
 w = inf, ((valor == Fp_info :: quiet_NaN ())) = falso Éxito

 v = nan, ((ilogb (value) == 0x7fffffff)) = true Éxito
 u = 3.14, ((ilogb (valor) == 0x7fffffff)) = falso Éxito
 w = inf, ((ilogb (value) == 0x7fffffff)) = true FAILED

 v = nan, (isunordered (1.2345, value)) = true Éxito
 u = 3.14, (no está ordenado (1.2345, valor)) = falso Éxito
 w = inf, (no solicitado (1.2345, valor)) = falso Éxito

 v = nan, (is_ieee754_nan (value)) = true Éxito
 u = 3.14, (is_ieee754_nan (value)) = falso Éxito
 w = inf, (is_ieee754_nan (value)) = falso Éxito

 [C: \ my \ forums \ so \ 282 (detectar NaN)]
 > _

Summing up the above results, only direct testing of the bit-level representation, using the is_ieee754_nan function defined in this test program, worked reliably in all cases with both g++ and Visual C++.


Apéndice:
After posting the above I became aware of yet another possible to test for NaN, mentioned in another answer here, namely ((value < 0) == (value >= 0)) . That turned out to work fine with Visual C++ but failed with g++'s -ffast-math option. Only direct bitpattern testing works reliably.

A possible solution that would not depend on the specific IEEE representation for NaN used would be the following:

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

As for me the solution could be a macro to make it explicitly inline and thus fast enough. It also works for any float type. It bases on the fact that the only case when a value is not equals itself is when the value is not a number.

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

After reading the other answers I wanted something that would pass through the floating-point comparison warning and would not break under fast math. The following code appears to work:

 /* 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  * Works for IEEE 754 compliant floating-point representations * Also works for extended precision long double */ #include  template  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  /*If printNaN is true then only expressions that are detected as NaN print and vice versa.*/ template  void test(bool printNaN) { T v[10] = {-0.0, 0.0, -1.0, 1.0, std::numeric_limits::infinity(), -std::numeric_limits::infinity(), std::numeric_limits::denorm_min(), -std::numeric_limits::denorm_min(), std::numeric_limits::quiet_NaN(), std::numeric_limits::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(true); test(true); test(true); std::cout << std::endl << "Not NaNs:" << std::endl; test(false); test(false); test(false); return 0; } 

Considering that (x != x) is not always guaranteed for NaN (such as if using the -ffast-math option), I’ve been using:

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

Numbers can’t be both < 0 and >= 0, so really this check only passes if the number is neither less than, nor greater than or equal to zero. Which is basically no number at all, or NaN.

You could also use this if you prefer:

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

I’m not sure how this is affected by -ffast-math though, so your mileage may vary.

Esto funciona:

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

output: isnan

It seems to me that the best truly cross-platform approach would be to use a union and to test the bit pattern of the double to check for NaNs.

I have not thoroughly tested this solution, and there may be a more efficient way of working with the bit patterns, but I think that it should work.

 #include  #include  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; } 

The IEEE standard says when exponent is all 1s and mantissa is not zero, the number is a NaN. Double is 1 sign bit, 11 exponent bits and 52 mantissa bits. Do a bit check.

As comments above state a != a will not work in g++ and some other compilers, but this trick should. It may not be as efficient, but it’s still a way:

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

Basically, in g++ (I am not sure about others though) printf prints ‘nan’ on %d or %.f formats if variable is not a valid integer/float. Therefore this code is checking for the first character of string to be ‘n’ (as in “nan”)