Плавающая точка == когда-либо в порядке? - PullRequest
52 голосов
/ 13 января 2011

Только сегодня я наткнулся на стороннее программное обеспечение, которое мы используем, и в его примере кода было что-то вроде этого:

// Defined in somewhere.h
static const double BAR = 3.14;

// Code elsewhere.cpp
void foo(double d)
{
    if (d == BAR)
        ...
}

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

Кроме того, как насчет вызова, подобного foo(BAR)?Будет ли это всегда сравниваться равным, так как они оба используют один и тот же static const BAR?

Ответы [ 14 ]

1 голос
/ 30 апреля 2011

Допустим, у вас есть функция, которая масштабирует массив чисел с постоянным коэффициентом:

void scale(float factor, float *vector, int extent) {
   int i;
   for (i = 0; i < extent; ++i) {
      vector[i] *= factor;
   }
}

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

Если factor равно 1,0, то эта функция не работает, и вы можете вернуться, не выполняя никакой работы. Если factor равно именно 0,0, то это можно реализовать с помощью вызова memset, что, вероятно, будет быстрее, чем выполнение умножения с плавающей запятой по отдельности.

В справочной реализации функций BLAS в netlib такие методы широко используются.

1 голос
/ 14 января 2011

Да.1/x будет действительным, если x==0.Вам не нужен неточный тест здесь.1/0.00000001 отлично.Я не могу вспомнить ни одного другого случая - вы даже не можете проверить tan(x) на x==PI/2

0 голосов
/ 17 февраля 2012

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

Предположим, например, что у вас есть программа, которая печатает значения с плавающей запятойна экран, и что, если значение с плавающей запятой оказывается точно равным M_PI, то вы хотели бы, чтобы оно вместо этого выводило «pi».Если значение немного отклоняется от точного двойного представления M_PI, вместо этого будет напечатано двойное значение, которое одинаково допустимо, но немного менее читаемо для пользователя.

0 голосов
/ 13 января 2011

У меня есть программа для рисования, которая в основном использует плавающую точку для своей системы координат, поскольку пользователю разрешено работать с любой детализацией / масштабированием. То, что они рисуют, содержит линии, которые можно согнуть в созданных ими точках. Когда они перетаскивают одну точку поверх другой, они объединяются.

Чтобы выполнить «правильное» сравнение с плавающей запятой, мне нужно было бы найти некоторый диапазон, в котором можно считать точки одинаковыми. Поскольку пользователь может увеличивать до бесконечности и работать в пределах этого диапазона, и поскольку я не мог заставить кого-либо зафиксировать какой-либо диапазон, мы просто используем '==', чтобы увидеть, совпадают ли точки. Иногда возникает проблема, когда точки, которые должны быть одинаковыми, отклоняются на .000000000001 или около того (особенно около 0,0), но обычно это работает просто отлично. Должно быть трудно объединить точки без включенной оснастки ... или, по крайней мере, так работала оригинальная версия.

Иногда выкидывает группу тестирования, но это их проблема: p

Так или иначе, есть пример возможного разумного времени для использования '=='. Следует отметить, что решение заключается не столько в технической точности, сколько в пожеланиях клиента (или их отсутствии) и удобстве. Это не то, что должно быть так точно. Так что, если две точки не сливаются, когда вы ожидаете их? Это не конец света и не повлияет на «расчеты».

...