"- Мы все" уступаем " сравнивая плавающую точку с == или!= небезопасно"
У меня есть строка, которую я преобразую в двойник следующим образом:
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
//...
Как это должно быть решено?
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 }
Comments