c++ nan fast-math

c++ - NaN negativo no es un NaN?



fast-math (6)

Mientras escribe algunos casos de prueba, y algunas de las pruebas verifican el resultado de una NaN.

Intenté usar std::isnan pero las std::isnan :

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

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

Después de intentar usar el hecho de que NaN != NaN y de usar assert(x == x) , el compilador me hace un "favor" y optimiza el asert.

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

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


Esto es embarazoso.

La razón por la que el compilador (GCC en este caso) estaba optimizando la comparación e isnan devolvió el valor false fue porque alguien de mi equipo había activado -ffast-math .

De la documentación:

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

Fíjese en la oración final - -ffast-math es insegura.


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

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

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

EDITAR : Con -ffast-math , independientemente del interruptor -O , gcc 4.2.1 en Snow Leopard piensa que NAN == NAN es true , como NAN == -NAN . Esto podría potencialmente romper el código catastróficamente. -ffast-math dejar de -ffast-math o, al menos, realizar pruebas para obtener resultados idénticos en las compilaciones al usarla y no usarla ...


Esto se basa en el artículo de wikipedia publicado en los comentarios. Tenga en cuenta que no se ha probado en su totalidad, aunque 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ías considerar archivar un error con los chicos de GLibc en eso.


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

Si en su implementación no funciona correctamente (¿cuál es ese?), Puede implementar la suya propia, reinterpretando_casting a lo largo y haciendo magia con IEEE.


Puede comprobar los bits de número. IEEE 754 ha definido una máscara para NaN:

  • Un NaN de señalización se representa mediante cualquier patrón de bits entre X''7F80 0001 ''y X''7FBF FFFF'' o entre X''FF80 0001 ''y X''FFBF FFFF''.
  • Un NaN silencioso se representa mediante 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 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


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

Esto es lo que uso en mi suite de prueba:

#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