Безопасно ли проверять число с плавающей точкой на равенство 0,0? - PullRequest
7 голосов
/ 21 декабря 2011

Я знаю, что проверять поплавки на равенство опасно из-за погрешностей точности, но безопасно ли проверять ноль?Я могу вспомнить некоторые случаи, например, при оптимизации особых случаев в алгоритмах, где вы бы хотели это сделать.Вопрос касается чисел с плавающей запятой, но я полагаю, что ответ также относится и к удвоениям.

Рассмотрим следующий код:

float factor = calculateFactor();
if(factor != 0.0f)
    applyComplexAlgorithm(factor);

Ответы [ 3 ]

8 голосов
/ 21 декабря 2011

Безопасно в том смысле, что если значение установлено явно в 0.0f, оно вернет true там.

Это НЕ безопасно в том смысле, что вы не должны ожидать, что значение, полученное в результате вычислений, будет точно 0,0f.

Таким образом, вы действительно используете 0,0f в качестве специального магического значениясортирует, а не как реальное сравнение с нулем.

5 голосов
/ 21 декабря 2011

Нет, это небезопасно, потому что вычисление в calculateFactor(), вероятно, не приведет к 0,0, даже если это арифметически должно.Тривиальный пример: (0,4-0,1) -0,3 при использовании double приводит к 5,551115123125783e-17

3 голосов
/ 21 декабря 2011

Это, конечно, безопасно , но вы должны подумать, что это значит для ваших алгоритмов.Если ваш алгоритм использует factor в качестве делителя (и сам по себе не проверяет деление на ноль), тогда да, вполне разумно проверить на factor != 0.0f перед вызовом applyComplexAlgorithm(factor).

Сейчасто, стоит ли вам проверять значение меньше чем несколько эпсилонов перед использованием factor, полностью зависит от того, что означает ваш код, и не может быть определено отдельно от предоставленного вами кода.

Если(как вы упомянули в другом комментарии) вы хотите использовать специальное значение 0.0f в качестве дозорного значения, которое означает что-то конкретное (например, неспособность вычислить коэффициент), тогда да, сравнивать абсолютно безопасно, используя ==,Например, использование следующего кода 0.0f является детерминированным и никогда не подвергается какой-либо ошибке округления:

float calculateFactor()
{
    int phase = moon_phase();
    if (phase == FULL) {  // whatever special case requires returning 0.0f
        return 0.0f;
    } else {
        return 1.0 + (phase * phase); // something that is never 0.0f
    }
}

float factor = calculateFactor();
if(factor != 0.0f)
    applyComplexAlgorithm(factor);
...