@shaukote

Какой смысл имеет константа FLT_EPSILON?

Как известно, в С, в файле 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)
  • Вопрос задан
  • 4665 просмотров
Решения вопроса 1
tsarevfs
@tsarevfs
C++ developer
Нагуглил такое определение.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
Ух... жаль что я не помню правил округления и нюансов с приведением типов... И все же спрошу - а почему вы там приводите все это добро к INT-у?
Ответ написан
@artem_tamazov
> 0x33800001 - которое на целый десятичный порядок меньше FLT_EPSILON (оно 0x34000000).

Оно равно половине FLT_EPSILON + еще чуть чуть (raw value of exponent is 0x67, while raw exponent of FLT_EPSILON is 0x68). Этого хватает, чтобы при сложении этого числа с 1.0 в режиме округления "к ближайшему" у вас получилось то же самое, что и (1.0f + FLT_EPSILON).
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы