2016-05-06 5 views
1

Я тестирую несколько бит кода, число, которое включает вычисление с использованием значений с плавающей запятой - часто их очень много. У меня есть общий (C++ - templated, но это не имеет большого значения для этого вопроса) код, который сравнивает мои результаты, будь то скалярные или массивы, против их ожидаемых значений.Что такое хороший выбор метода сравнения чисел с плавающей запятой?

Я столкнулся с проблемой выбора прецизионного порога, по крайней мере для двух типов с плавающей запятой C/C++ float и double - для различных функций, которые я тестирую. Как и в случае well known, для сравнения значений с плавающей запятой нет единого размера, а не единственное значение точности, которое подходит и вычисляется, основываясь исключительно на типе данных: Относительная и абсолютная ошибка, многочисленные операции, которые могут увеличиваться ошибки округления с плавающей запятой, вычисления, которые должны быть равны 0, поэтому вы не можете нормализовать ожидаемое значение и т. д.

Что такое общепринятый подход/алгоритм/правило для большого пальца выбор метода сравнения (и порогов равенства) для значений с плавающей запятой?

ответ

0

Существует нет вообще-разумный подход :-(

одно важное свойство чисел является то, что набор чисел можно разделить на классы эквивалентности, где все члены одного и того же класса эквивалентности «равны» в каком-то смысле и все члены двух разных классов эквивалентности «не равны». Это свойство имеет важное значение для сортировки алгоритмов и хеширования.

Если вы берете двойную с 53-битной мантиссой и просто заменяете последние бит мантиссы нулями, то у вас все еще есть классы эквивалентности, и сортировка/хеширование будут работать нормально. С другой стороны, два числа могут быть сколь угодно близко друг к другу и по-прежнему сравнивать с Этот метод.

Другой метод имеет алгоритм, который решает, являются ли два числа «возможно равными». Вы можете основывать все остальное на этом. Например, a «определенно больше», чем b, если a> b и a не «возможно равны» b. a «возможно больше», чем b, если a> b или a «возможно равны» b.

Сортировка проблематична. У вас может быть «возможно равным» b, а b «возможно равным» c, но a не «возможно равным» c.

Если вы используете double с 53-битной мантиссой, то маловероятно, что два несвязанных числа равны даже в 45 бит. Таким образом, вы вполне можете проверить, является ли абсолютная величина разницы меньше абсолютного значения большего числа, деленная на 2^45. Ваш пробег будет значительно отличаться. Важно то, думаете ли вы, что 0 должно быть равно очень маленьким числам или нет.

1

Мне нравится подход, используемый в googletest, например. EXPECT_DOUBLE_EQ (a, b) и EXPECT_FLOAT_EQ (a, b): цифры приблизительно равны, если они находятся в пределах 4 единиц в последней позиции (4 ULP). Чтобы сделать это, вы

  1. новообращенный зарегистрированны величина для компенсации
  2. вычесть, как если бы они были целыми
  3. проверить, что разница < = 4.

Это автоматически масштабируется для величины и расслабляет к абсолютному нулю.

Смежные вопросы