Сравнение чисел с плавающей запятой в C

у меня есть double что печатает как 0.000000 и я пытаюсь сравнить его с 0.0f, но безуспешно. Почему есть разница? Каков самый надежный способ определить, равен ли ваш двойник нулю?

4 ответов


чтобы определить, достаточно ли близко к нулю, что он будет печатать как 0.000000 до шести знаков после запятой, что-то вроде:

fabs(d) < 0.0000005

работа с небольшими неточностями в расчетах с плавающей запятой может стать довольно сложной в целом, хотя.

если вы хотите лучше понять, какое значение у вас есть, попробуйте распечатать с помощью %g вместо %f.


вы можете сделать выбор. Как -0.00001


Это фундаментальная проблема с арифметикой с плавающей запятой на современных компьютерах. Они по своей природе неточны и не могут быть достоверно сопоставлены. Например, язык 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;
}