2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




 
 сравнение double в c++
Сообщение12.12.2011, 10:48 
В файле float.h находится константа DBL_EPSILON, которая равна минимальному x такому, что 1.0 + x > x. И далее везде в интернетах утверждается, что для сравнения на равенство чисел a и b достаточно написать
Используется синтаксис C++
if (fabs(a-b) <= DBL_EPSILON*fmax(fabs(a), fabs(b))) {
  // a == b с относительной точностью DBL_EPSILON
}
 


Почему это так? Откуда такое неравенство?

 
 
 
 Re: сравнение double в c++
Сообщение12.12.2011, 14:20 
Аватара пользователя
На самом деле вопрос сравнения чисел с плавающей точкой, увы, не прост.
Ошибки округления могут накапливаться, и нужно их как-то оценивать.
Если в Вашем примере a и b имеют тип float или double (и отключена оптимизация, позволяющая хранить промежуточные результаты в регистрах), то проще будет написать (a == b) — результат будет тот же (хотя насчёт double я не совсем уверен, но практический смысл расписывать "длинный" способ отсутствует).
Вообще, "длинный" способ, конечно, корректнее, но тут нужно:
1) подобрать правильное EPSILON;
2) отдельно рассмотреть случай, когда числа a и b близки к нулю.
Оба пункта нужно рассматривать исходя из практических соображений, которые в каждом случае разные.
Например, я в одной из расчётных программ использовал примерно такую функцию:
Используется синтаксис C
bool areEqual(double x, double y)
{
  static double SMALL_NUM = 1.0E-5;
  if (abs(x) < SMALL_NUM && abs(y) < SMALL_NUM)
    return abs(x-y) < SMALL_NUM;
  else
    return abs(x-y) < abs(x) * SMALL_NUM;
}
Всё работало отлично, пока не пришлось работать с физическими величинами в мелком масштабе (порядок величины в единицах СИ — $10^{-6}$). Такие переменные пришлось сравнивать с нулём по-другому :-(

 
 
 
 Re: сравнение double в c++
Сообщение12.12.2011, 14:34 
Аватара пользователя
Относительная погрешность $\varepsilon$ и абсолютная погрешность $\Delta$ при известной величине $v$ связаны между собой как $\varepsilon=\Delta/v,$ $\Delta=\varepsilon v.$

Так что, когда вам надо найти, что числа равны с заданной погрешностью, $\lvert a-b\rvert\leqslant\Delta,$ то вы оцениваете $\Delta=\max\{\Delta_a,\Delta_b\},$ где $\Delta_a=\varepsilon a,$ $\Delta_b=\varepsilon b.$

В принципе, выбор наибольшей $\Delta$ - стандартная процедура - в данном случае перестраховка, поскольку если две величины будут различаться по порядку величины, то и между собой они равны не будут. С другой стороны, она обеспечивает хотя бы коммутативность отношения: $a\approx b\Leftrightarrow b\approx a,$ хотя уже ни о какой транзитивности речь не идёт.

И совет на будущее: никогда не полагайтесь на сравнения с погрешностью DBL_EPSILON. Если у вас есть два числа, которые надо сравнить, то они откуда-то происходят, из каких-то измерений или расчётов, и их погрешность всегда выше, чем DBL_EPSILON. Правильно в таком случае использовать погрешность вычислений или измерений, которую вы оцениваете или сами, или требуете от того, кто предоставляет вам сами числа.

 
 
 
 Re: сравнение double в c++
Сообщение12.12.2011, 18:05 
max(Im) в сообщении #514633 писал(а):
которая равна минимальному x такому, что 1.0 + x > x

точнее должно быть x>0, а далее по вашему тексту. Константы такие машинно-зависимые. В CBuilder6 их 3 для разных типов чисел с плавающей запятой.
Код:
#define DBL_EPSILON         2.2204460492503131E-16
#define FLT_EPSILON         1.19209290E-07F
#define LDBL_EPSILON        1.084202172485504434e-019L


max(Im) в сообщении #514633 писал(а):
Почему это так?

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

 
 
 [ Сообщений: 4 ] 


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group