Сравнение чисел с плавающей запятой в C
У меня есть double
который печатает как 0.000000
и я пытаюсь сравнить его с 0.0f
, безуспешно. Почему здесь разница? Какой самый надежный способ определить, равен ли ваш двойник нулю?
Чтобы определить, достаточно ли он равен нулю, он будет печатать от 0.000000
до шести знаков после запятой, например:
fabs(d) < 0.0000005
Тем не менее, обработка небольших неточностей в вычислениях с плавающей запятой может быть довольно сложной.
Если вы хотите лучше понять, какое значение у вас есть, попробуйте выполнить печать с %g
вместо %f
.
Вы можете сделать диапазон. Например -0.00001 <= x <= 0.00001
Это фундаментальная проблема с арифметикой с плавающей запятой на современных компьютерах. Они по своей природе неточны и не могут быть надежно сопоставлены. Например, язык ML явно запрещает сравнение равенства для реальных типов, потому что он считается слишком опасным. См. Также отличную (если немного длинную и математически ориентированную) статью Дэвида Голдберга по этой теме.
Edit: tl; dr: вы можете делать это неправильно.
Кроме того, часто забываемыми функциями числа с плавающей запятой являются денормализованные числа. Это числа, которые имеют минимальный показатель, но не подходят в диапазоне 0,5-1.
Эти числа ниже FLT_MIN для float и DBL_MIN для double.
Общей ошибкой с использованием порога является сравнение двух значений или использование FLT_MIN / DBL_MIN в качестве предела.
Например, это приведет к нелогичному результату (если вы не знаете о денормалах):
bool areDifferent(float a, float b) { if (a == b) return false; // Or also: if ((a - b) == FLT_MIN) return true; } // What is the output of areDifferent(val, val + FLT_MIN * 0.5f) ? // true, not false, even if adding half the "minimum value".
Денормалы также обычно подразумевают потерю производительности при вычислении. Тем не менее, вы не можете их отключить, иначе такой код может генерировать исключение с плавающей запятой DIVIDE BY ZERO (если включено):
float getInverse(float a, float b) { if (a != b) return 1.0f / (ab); // With denormals disabled, a != b can be true, but (a - b) can still be denormals, it'll rounded to 0 and throw the exception return FLT_MAX; }