2010-08-29 22 views
28

Al escribir algunos casos de prueba, y algunas de las pruebas comprobar el resultado de un NaN.¿NaN negativo no es un NaN?

He intentado utilizar std::isnan pero los failes de aserción:

Assertion `std::isnan(x)' failed. 

Después de imprimir el valor de x, resultó que es NaN negativo (-nan) que es totalmente aceptable en mi caso.

Después de tratar de usar el hecho de que NaN != NaN y usando assert(x == x), el compilador me hace un 'favor' y optimiza la afirmación de distancia.

Haciendo mi propia función isNaN se está optimizando lejos también.

¿Cómo puedo verificar la igualdad de NaN y -NaN?

+7

o_O? Negativo NaN * es * NaN. – kennytm

+1

¿Podría mostrar cómo escribe su propio 'isNaN', y quizás el incorporado de su compilador si lo tiene? Una manera de probar ** a ** NaN (hay varios, como habrás notado) es probar el patrón de bits en http://en.wikipedia.org/wiki/NaN (el exponente es 11..11). –

+0

¿Qué compilador estás usando y cómo es tu código de prueba? – jalf

Respuesta

31

Esto es embarazoso.

La razón por la que el compilador (GCC en este caso) ha sido optimizar la comparación de distancia y isnan volvió false era porque alguien de mi equipo se había convertido en -ffast-math.

A partir de los documentos:

 
-ffast-math 
    Sets -fno-math-errno, -funsafe-math-optimizations, 
    -fno-trapping-math, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans and fcx-limited-range. 

    This option causes the preprocessor macro __FAST_MATH__ to be defined. 

    This option should never be turned on by any -O option since it can result in incorrect output for programs which depend on an exact implementation of IEEE or ISO rules/specifications for math functions. 

Aviso la sentencia final - -ffast-math es inseguro.

+0

Acabo de ver exactamente el mismo problema con el compilador de MS cuando se usa con/fp: indicador rápido. Funciona bien con/fp: sin embargo, precisa. – stijn

0

Hay C99 isnan() que deberías poder utilizar.

Si en su aplicación no funciona correctamente (que es eso?) Puede implementar su propia, por reinterpret_casting a largo y hacer magia IEEE bits.

+2

Ese 'isnan' es exactamente lo que ya está usando. –

-3

Esto se basa en el artículo de wikipedia publicado en los comentarios. Tenga en cuenta que no ha sido probado por completo; sin embargo, debería darle una idea de algo que puede hacer.

bool reallyIsNan(float x) 
{ 
    //Assumes sizeof(float) == sizeof(int) 
    int intIzedX = *(reinterpret_cast<int *>(&x)); 
    int clearAllNonNanBits = intIzedX & 0x7F800000; 
    return clearAllNonNanBits == 0x7F800000; 
} 

EDIT: Realmente creo que debería considerar la presentación de un error con los chicos glibc en que uno sin embargo.

+0

Esto devolverá 'true' para' Inf' también. –

+0

@Sam: Como dije, no lo probé, lo obtuve de Wikipedia. Nunca hice ningún reclamo sobre su corrección. En cualquier caso, el OP ya respondió esta pregunta. No veo por qué estamos desenterrando una pregunta de hace un año que ya estaba marcada como respuesta y quejándose de ella. –

+4

No me quejo; usted está. Encontré esta pregunta en una búsqueda de Google y vi que no tenía una respuesta satisfactoria. Estoy comentando respuestas incorrectas o incompletas porque no quiero que nadie más pase tiempo averiguando por qué son incorrectas o incompletas. Además, la respuesta aprobada da una explicación, no una solución. La edad de esta pregunta no tiene ninguna relevancia. Si tienes un problema con eso, probablemente te pierdas el objetivo de este sitio web. Solo relájate, amigo. –

0

Puede verificar los bits del número. IEEE 754 ha definido máscara para NaN:

  • A señalización NaN está representado por cualquier patrón de bits entre X'7F80 0001' y X'7FBF FFFF 'o entre X'FF80 0001' y X'FFBF FFFF'.
  • Un tranquilo NaN está representado por cualquier patrón de bits entre X'7FC0 0000' y X'7FFF FFFF 'o entre X'FFC0 0000' y X'FFFF FFFF'.

Esto podría no ser portátil, pero si está seguro acerca de su plataforma, puede ser aceptable. Más: http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlf101l.doc/xlfopg/fpieee.htm

+0

Ese hubiera sido mi último recurso, todavía estoy tratando de encontrar la solución más portátil. – LiraNuna

+0

@LiraNuna no es tan dramático. Si lo implementa teniendo en mente a los endianios, será lo suficientemente portátil como – Andrey

1

Esto parece un error en la ejecución de su biblioteca de isnan() a mí. Funciona bien aquí en gcc 4.2.1 en Snow Leopard. Sin embargo, ¿qué hay de intentar esto?

std::isnan(std::abs(yourNanVariable)); 

Obviamente, no puedo probarlo, ya que es std::isnan(-NaN)true en mi sistema.

EDITAR: Con -ffast-math, independientemente del interruptor -O, gcc 4.2.1 en Snow Leopard piensa que es NAN == NANtrue, como es NAN == -NAN. Esto podría potencialmente romper el código catastróficamente. Aconsejaría dejar -ffast-math o al menos probar los resultados idénticos en las compilaciones que usan y no lo usan ...

3

Se espera que isnan() tenga un comportamiento indefinido con -ffast-math.

Esto es lo que yo uso en mi banco de pruebas:

#if defined __FAST_MATH__ 
# undef isnan 
#endif 
#if !defined isnan 
# define isnan isnan 
# include <stdint.h> 
static inline int isnan(float f) 
{ 
    union { float f; uint32_t x; } u = { f }; 
    return (u.x << 1) > 0xff000000u; 
} 
#endif