Сравнение чисел с плавающей запятой в C
у меня есть double
что печатает как 0.000000
и я пытаюсь сравнить его с 0.0f
, но безуспешно. Почему есть разница? Каков самый надежный способ определить, равен ли ваш двойник нулю?
4 ответов
чтобы определить, достаточно ли близко к нулю, что он будет печатать как 0.000000
до шести знаков после запятой, что-то вроде:
fabs(d) < 0.0000005
работа с небольшими неточностями в расчетах с плавающей запятой может стать довольно сложной в целом, хотя.
если вы хотите лучше понять, какое значение у вас есть, попробуйте распечатать с помощью %g
вместо %f
.
Это фундаментальная проблема с арифметикой с плавающей запятой на современных компьютерах. Они по своей природе неточны и не могут быть достоверно сопоставлены. Например, язык ML явно запрещает сравнение равенства на реальных типах, поскольку он считался слишком небезопасным. Смотрите также отличный (если немного длинный и математически ориентированный) статьи Дэвид Голдберг на эту тему.
Edit: tl;dr: возможно, вы делаете это неправильно.
кроме того, одним из часто упускаемых из виду особенностей числа с плавающей запятой являются денормализованные числа. Это числа, которые имеют минимальный показатель, но не вписываются в диапазон 0,5-1.
цифры ниже чем FLT_MIN для float, и DBL_MIN для double.
распространенной ошибкой при использовании порога является сравнение двух значений или использование FLT_MIN/DBL_MIN в качестве предела.
например, это приведет к нелогичному результату (если вы не знаете о denormals):
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".
Denormals также, как правило, подразумевает потерю производительности в вычислениях. Тем не менее, вы не можете отключить их, иначе такой код все равно может создать исключение деления на ноль с плавающей запятой (если включено):
float getInverse(float a, float b) {
if (a != b)
return 1.0f / (a-b); // 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;
}