Как вычислить погрешность, при которой два числа с плавающей точкой можно считать равными?

При реализации алгоритмов вычислительной геометрии, пользуясь книгой Окулова "Программирование в алгоритмах", столкнулся с проблемой использования "магического" числа, а точнее реализация алгоритма в книге подразумевала погрешность в 10^(-3) и меня заинтересовало откуда было взято это число.

Алгоритм проверки равенства:
ЕСЛИ |a - b| <= eps ТО числа равны
ИНАЧЕ числа не равны,
где eps - и есть та самая погрешность.
  • Вопрос задан
  • 5018 просмотров
Пригласить эксперта
Ответы на вопрос 8
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Если речь идёт об абстрактной математике, то надо рассматривать представление плавающего типа (float, double, long double) в конкретной архитектуре. В большинстве случаев используется IEEE 754-1985. Скажем, для float32 в нормализованной форме точность - то есть единица младшего разряда мантиссы - в зависимости от экспоненты может быть от 1.175494351×10−38 до 3.402823466×1038.

Если же речь о прикладных задачах, то точность выбирается исходя из модели процесса. Скажем, при поиске кратчайшего маршрута поездки достаточно точности в десяток метров, а при парковке нужны, как минимум, сантиметры.
Ответ написан
Один из подходов к определению точности - вести "двойные" вычисления:
ведется обычный счет + в каждой формуле вычисляется погрешность итогового результата (исходя из входных погрешностей операндов и вида операций).
К тому моменту, когда Вы подойдете к сравнению двух чисел a и b - Вам будет достаточно удостовериться, что их интервалы с учетом погрешностей не пересекаются.

Заранее вычислить число eps возможно только в очень простых случаях.
Более того, указывать его фиксированным в общем случае - совершенно неправильно.
А что если Вы вычисляете треугольник со сторонами в миллиметры ?
А что если у Вас угол при вершине всего полградуса ?
Ответ написан
@mrgloom
en.wikipedia.org/wiki/Machine_epsilon
What every scientist should know about floating-po...
www.parashift.com/c++-faq/floating-point-arith.html

наверно тут надо использовать std::numeric_limits::epsilon
#include <cmath>  /* for std::abs(double) */

inline bool isEqual(double x, double y)
{
  const double epsilon = /* some small number such as 1e-5 */;
  return std::abs(x - y) <= epsilon * std::abs(x);
  // see Knuth section 4.2.2 pages 217-218
}
Ответ написан
@DancingOnWater
Погрешность связана с процедурой измерения.

Применительно к численным вычислениям это означает следущее:
1) Если две различные реализации одного и тогоже схожи (наличествуют большие куски одного и тогоже кода), то точность определяется стандартом чисел, в которых идет вычисления (про это и говорил Rsa97)
2)В противном случае точность оценивается в рамках той задачи, которая решается. Приведу пример на примере решения задач небесной механики.
a) Решается научная задача по моделирования движения небесных тел. Тогда получаемая погрешность = погрешности модели.
б) Решается прикладная задача по вычислению положения спутника. Тогда погрешность = предъявляемым требованиям.
Ответ написан
tsarevfs
@tsarevfs
C++ developer
Существуют техники позволяющие точно вычислить eps. Однако, точно проверить число на равенство 0 несколько сложнее. Пусть res - результат выражения, err - погрешность вычислений. Тогда |res| + |err| должно быть < eps. Для того, чтобы обеспечить это приходится использовать длинную арифметику и считать десятки тысяч знаков в числе. Однако в практических задачах математическая точность fp-вычислений важна не часто.
Ответ написан
KOLANICH
@KOLANICH
Знаю JS, PHP, C++, C#
во всех нормальных ЯП есть константа, обычно зовётся EPS или EPSILON
А в принципе вычислить можно
Числа с плавающей точкой - это мантисса и экспонента
тебе нужна самая маленькая экспонента и самая маленькая мантисса - это и будет эпсилоном
но для этого нужно знать, как хранятся в памяти
проще использовать константу, тем паче что она одинакова для всех ЯП, использующих "железную" реализацию чисел с плавающей точкой
Ответ написан
afiskon
@afiskon
Это зависит от задачи и бизнес требований. Вот например работаете вы с деньгами. Там флоаты не используются, но в результате взятия комиссий, умножения на кросскурсы и так далее происходит аналогичная проблема - есть число с большим количеством знаков после запятой и нужно понять равны они (например, сравнение с нулем) или нет. Тут можно взять эпсилон 0.005, так как для человека если две суммы отличаются меньше чем на пол цента, то их можно считать равными. В каких-то физических измерениях можно отталкиваться от погрешности приборов. Ну и так далее.
Ответ написан
rafuck
@rafuck
Обычно правильней вычислять относительную погрешность:
|a-b|/max{|a|, |b|} < eps
но нужно отдельно обрабатывать случай деления на ноль, что-то вроде этого:
(a == b || fabs(a-b)/max(fabs(a), fabs(b)))
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы