Эпсилон изменяется в зависимости от значения в двойном диапазоне.Если вы хотите использовать свои собственные и исправленные эпсилон, я рекомендую выбрать эпсилон для 1
.
fabs(a1-a2) < epsilon
Это не идеально.Если a1
и a2
являются результатом операций с маленькими числами, эпсилон будет маленьким.Если a1
и a2
являются результатом операций с большими числами, эпсилон будет большим.
fabs((a1-a2)/a2) < epsilon
Это немного лучше, поскольку вы хотите масштабировать epsilon
на a2
.Однако есть деление на 0
, если a2
равно 0
.
fabs(a1-a2) < fabs(a2)*epsilon
Это немного лучше.Однако это неверно, если a2
равно 0
.fabs(a2)*epsilon
будет равно 0
, и сравнение двух значений a1=0.000000001
и a2=0
всегда будет неудачным.
fabs(a1-a2) < max(fabs(a1), fabs(a2))*epsilon
Это немного лучше.Однако это неверно, поскольку epsilon
не пропорционально непрерывно .При кодировании IEEE epsilon
пропорционально значению дискретно на основе 2
.
fabs(a1-a2) < 2^((int)log2(max(fabs(a1), fabs(a2)))*epsilon
Это выглядит корректно для меня, когда и a1
и a2
не равны 0
.
Реализация универсального метода может быть:
bool nearly_equal(double a1, double a2, double epsilon)
{
if (a1 == 0 && a2 == 0)
return true;
return std::abs(a1 - a2) < epsilon * pow (2.0, static_cast<int> (std::log2(std::max(std::abs(a1), std::abs(a2)))));
}