Подтвердить что ты не робот

Можем ли мы полагаться на op == для двоичного сравнения значений с плавающей запятой?

Мы все знаем (правильно?!), что нельзя сравнивать значения с плавающей запятой, проверяя на равенство (operator==).

Но что, если я действительно хочу определить, являются ли два float a и b равными двоичным? Если им не разрешено быть NaN (или другими "специальными значениями" ), это "безопасно"? Могу ли я полагаться на operator== для работы таким образом?

4b9b3361

Ответ 1

(Предполагая представления IEEE-754) почти, но не совсем. Если вы можете исключить NaN, вам все равно нужно иметь дело с тем, что +0.0 и -0.0 имеют разные двоичные кодировки, но сравнивают одинаковые (потому что оба точно равны нулю).

Конечно, С++ не требует IEEE-754. Так что, строго говоря, все ставки отключены.

Если вы хотите проверить равенство (в) равенства, просто используйте memcmp(&a, &b, sizeof a).

Ответ 2

В принятом ответе игнорируется очень важный аспект: расширенная точность с плавающей запятой. ЦП может выполнять вычисления с размером бит, превышающим размер вашего хранилища. Это будет особенно верно, если вы используете float, но также может быть правдой для double и других типов с плавающей запятой.

Чтобы показать проблему, следующий assert может фактически выходить из строя в зависимости от того, как была выполнена компиляция и как работает чип.

  void function( float a )
  {
     float b = a / 0.12345;
     assert( b == (a/0.12345) );
  }

Теперь, в этом приведенном примере, он, вероятно, всегда пройдет, но есть много случаев, когда этого не произойдет. Просто посмотрите GCC Bug 323 и посмотрите, сколько дефектов отмечены как дубликаты. Эта расширенная точность вызывает проблемы для многих людей, и это может также вызвать проблемы для вас.

Если вам нужна гарантия, что вам нужно будет сделать, это сделать функцию сравнения, которая принимает два параметра float и гарантирует, что функция никогда не будет встроена (сохраненные поплавки не подвержены расширенной точности). То есть вы должны убедиться, что эти поплавки фактически сохранены. Существует также опция GCC, называемая "store-float", которая, как я полагаю, блокирует хранение, возможно, она может использоваться здесь для вашей индивидуальной функции.

Ответ 3

Чтобы убедиться, что значение с плавающей запятой не NaN, вы можете сравнить его с собой:

double foo;
// do something with foo
if (foo != foo) {
    std::cout << "Halp! Foo is NaN!";
}

Я уверен, что это гарантировано стандартом IEEE-754.