Сегодня я отслеживал, почему моя программа получала некоторые неожиданные ошибки несоответствия контрольной суммы, в некотором написанном мною коде, который сериализует и десериализует значения с плавающей точкой IEEE-754, в формате, который включает 32-битное значение контрольной суммы (который вычисляется путем запуска алгоритма типа CRC над байтами массива с плавающей запятой).
После небольшого разбора головы я понял, что проблема в том, что 0.0f и -0.0f имеют разные биты-patterns (0x00000000 против 0x00000080 (little-endian), соответственно), но они считаются эквивалентными оператором равенства C ++.Итак, ошибки несоответствия контрольной суммы произошли потому, что мой алгоритм вычисления контрольной суммы уловил разницу между этими двумя битовыми шаблонами, в то время как некоторые другие части моей кодовой базы (которые используют тестирование на равенство с плавающей запятой, а не просматривали значения побайтнобайт) не делал этого различия.
Хорошо, достаточно справедливо - я, наверное, должен был бы знать лучше, чем проводить тестирование на равенство с плавающей точкой.
Но это заставило меня задуматься, а есть лидругие значения с плавающей точкой IEEE-754, которые считаются равными (согласно оператору C ==), но имеют разные битовые комбинации?Или, другими словами, как именно оператор == определяет, равны ли два значения с плавающей точкой?Я новичок, хотя он делал что-то вроде memcmp () на своих битовых шаблонах, но, очевидно, это более нюанс, чем это.
Вот пример кода того, что я имею в виду, на случай, если я не понял выше.
#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;
}