"- Мы все" уступаем " сравнивая плавающую точку с == или!= небезопасно"



У меня есть строка, которую я преобразую в двойник следующим образом:

double d = [string doubleValue];

Документация для doubleValue говорит нам, что при переполнении этот метод возвращает либо HUGE_VAL, либо -HUGE_VAL. Вот как я проверял это ранее:

if (d == HUGE_VAL || d == -HUGE_VAL)
   //overflow

Теперь, после добавления нового предупреждающего флага "-Weverything", компилятор жалуется, что

Comparing floating point with == or != is unsafe

Как я могу решить эту проблему? Как я должен проводить эти сравнения?


У меня также есть тот же вопрос о сравнении двух "нормальные "числа с плавающей запятой (то есть не" HUGE_VAL"). Например,

double a, b;
//...
if (a != b) //this will now yield the same warning
  //...

Как это должно быть решено?

197   4  

4 ответов:

Вам не нужно беспокоиться об этом предупреждении. Это нонсенс во многих случаях, в том числе и в вашем.

Документация doubleValue не говорит, что она возвращает что-то достаточно близкое к HUGE_VAL или -HUGE_VAL при переполнении. Он говорит, что возвращает именно эти значения в случае переполнения.

Другими словами, значение, возвращаемое методом в случае переполнения, сравнивает == с HUGE_VAL или -HUGE_VAL.

Почему предупреждение существует в первом место?

Рассмотрим пример

. Этот пример оценивается как ложный. Люди, включая авторов предупреждения, с которым вы познакомились, думают, что плавающая точка == является неточной, и что неожиданный результат происходит из этой неточности.

Все они ошибаются.

С плавающей запятойсложение является "неточным", в некотором смысле неточным: оно возвращает ближайшее представимое число с плавающей запятой для запрошенной операции. В примере выше, преобразования (от десятичной до с плавающей запятой) и сложение с плавающей запятой являются причинами странного поведения.

С другой стороны, равенство

С плавающей запятойработает почти так же, как и для других дискретных типов. Равенство с плавающей запятой является точным: за исключением незначительных исключений (значение NaN и случай +0. и -0.), равенство принимает значение true тогда и только тогда, когда два рассматриваемых числа с плавающей запятой имеют одинаковое представление.

Ты не нужен Эпсилон, чтобы проверить, равны ли два значения с плавающей запятой. И, как говорит Дьюар по существу , предупреждение в примере 0.3 + 0.4 == 0.7 должно быть на +, а не на ==, Чтобы предупреждение имело смысл.

Наконец, сравнение с внутри Эпсилона означает, что значения, которые не равны, будут выглядеть равными, что не подходит для всех алгоритмов.

В этом случае попробуйте использовать >= и <=.

Если вы уверены в своем сравнении и хотите, чтобы оно зазвенело, окружите свой код:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wfloat-equal"
/* My code triggering the warnings */
#pragma clang diagnostic pop

Поплавки не следует сравнивать с == или != из-за неточности типа float, что может привести к неожиданным ошибкам при использовании этих операторов. Вы должны проверить, лежат ли поплавки на расстоянии друг от друга ( называемом "Эпсилон" большую часть времени ).

Это может выглядеть так:

const float EPSILON = 1.0f; // use a really small number instead of this

bool closeEnough( float f1, float f2)
{
    return fabs(f1-f2)<EPSILON; 
    // test if the floats are so close together that they can be considered equal
}
    Ничего не найдено.

Добавить ответ:
Отменить.