Как известно, в С, в файле float.h, есть константа FLT_EPSILON (и аналогичная DBL_EPSILON, но сейчас речь не о ней).
Я всегда был уверен, она представляет собою наименьшее число, такое, что что 1.0 + FLT_EPSILON != 1.0.
Однако на днях, изучая внутренности float, мягко говоря усомнился в этом.
Если оно наименьшее, то следующий код должен вывести два одинаковых значения:
int repr(float f)
{
return *(int*) &f;
}
float from_repr(int i)
{
return *(float*) &i;
}
int main()
{
float one = 1.0f;
float prev_flt_epsilon = from_repr(repr(FLT_EPSILON) - 1); // предыдущее число
printf("%x\n", repr(one));
printf("%x\n", repr(one + prev_flt_epsilon));
}
Однако ж - нет, на выходе получаем 0x3f800000 и 0x3f800001.
Идём дальше:
// функции repr() и from_repr() те же
int main()
{
float one = 1.0f;
float eps = 0.0f;
while (repr(one) == repr(one + eps)) {
eps = from_repr(repr(eps) + 1);
}
printf("%x\n", repr(eps));
}
Получаем 0x33800001 - которое на целый десятичный порядок меньше FLT_EPSILON (оно 0x34000000).
То есть получается, FLT_EPSILON - далеко не
наименьшее число, которое при прибавлении к 1.0 меняет его значение?
Или я чего-то не понимаю?
P.S. Извиняюсь, если кому-то покажется излишне громоздким мой огород с repr() и from_repr(), давно не писал на С, поэтому вынес работу с указателями во внешние функции, чтобы не напутать ничего.
P.P.S. На всякий случай:
[shau-kote@sh-arch ~]$ gcc --version
gcc (GCC) 4.9.0 20140604 (prerelease)