Hoy estaba rastreando por qué mi programa obtenía algunos errores inesperados de suma de comprobación, en algún código que escribí que serializa y deserializa valores de coma flotante IEEE-754, en un formato que incluye un valor de suma de comprobación de 32 bits (que se calcula ejecutando un algoritmo de tipo CRC sobre los bytes de la matriz de coma flotante).¿Cómo el operador C == decide si dos valores de coma flotante son iguales o no?
Después de un poco de rascarse la cabeza, me di cuenta de que el problema era 0.0f y -0.0f tienen patrones de bits diferentes (0x00000000 vs 0x00000080 (little-endian), respectivamente), pero se consideran equivalentes por C++ igualdad-operador. Entonces, los errores de suma de comprobación no ocurrieron porque mi algoritmo de suma de comprobación recogió la diferencia entre esos dos patrones de bits, mientras que otras partes de mi base de código (que usan pruebas de igualdad de coma flotante, en lugar de mirar los valores byte por by byte) no hizo esa distinción.
De acuerdo, es justo: probablemente debería haber sabido que no debía hacer pruebas de igualdad de punto flotante de todos modos.
Pero esto me hizo pensar, ¿hay otros valores de punto flotante IEEE-754 que se consideran iguales (según el operador C ==) pero tienen diferentes patrones de bits? O, para decirlo de otra manera, ¿cómo exactamente el operador == decide si dos valores de coma flotante son iguales? Newbie me creo que estaba haciendo algo parecido a memcmp() en sus patrones de bits, pero claramente es más matizado que eso.
Aquí hay un ejemplo de código de lo que quiero decir, en caso de que no fuera claro anteriormente.
#include <stdio.h>
static void PrintFloatBytes(const char * title, float f)
{
printf("Byte-representation of [%s] is: ", title);
const unsigned char * p = (const unsigned char *) &f;
for (int i=0; i<sizeof(f); i++) printf("%02x ", p[i]);
printf("\n");
}
int main(int argc, char ** argv)
{
const float pzero = -0.0f;
const float nzero = +0.0f;
PrintFloatBytes("pzero", pzero);
PrintFloatBytes("nzero", nzero);
printf("Is pzero equal to nzero? %s\n", (pzero==nzero)?"Yes":"No");
return 0;
}
http://how-to.wikia.com/wiki/Howto_compare_floating_point_numbers_in_the_C_programming_language su información, utilizando un épsilon es el camino a seguir para las comparaciones de flotación. No sobre el tema, pero útil para saber. – darvids0n
NaNs podría ir en cualquier dirección (posiblemente según el compilador). También pueden ser diferentes en memoria ya que hay una gran cantidad de NaN posibles (2^24-1 para precisión simple). – ughoavgfhw