我想知道在这两种方式之间比较两个双倍有什么区别:
double a1 = ...;
double a2 = ....;
有没有更好的方法呢?
感谢
答案 0 :(得分:13)
This article非常彻底地回答了你的问题。您可能希望跳到“Epsilon比较”部分。
答案 1 :(得分:3)
就我个人而言,我使用std::nextafter
来比较两个double
。这会对最小epsilon
的值(或factor
)使用最小epsilon
。
bool nearly_equal(double a, double b)
{
return std::nextafter(a, std::numeric_limits<double>::lowest()) <= b
&& std::nextafter(a, std::numeric_limits<double>::max()) >= b;
}
bool nearly_equal(double a, double b, int factor /* a factor of epsilon */)
{
double min_a = a - (a - std::nextafter(a, std::numeric_limits<double>::lowest())) * factor;
double max_a = a + (std::nextafter(a, std::numeric_limits<double>::max()) - a) * factor;
return min_a <= b && max_a >= b;
}
答案 2 :(得分:2)
前者仅比较绝对值,而第二个比较相对值。假设epsilon设置为0.1
:如果a1
和a2
较大,这可能就足够了。但是,如果两个值都接近于零,则第一种方法将考虑大多数值相等。
这实际上取决于您正在处理的是哪种值。如果您使用的是数学上更合理的第二种情况,请务必考虑案例a2==0
。
答案 3 :(得分:2)
这已经得到了很好的解决,但有几点是有道理的:
fabs(a1-a2) < epsilon
将a1
和a2
之间的绝对差异与容差epsilon
进行比较。如果您知道缩放先验(例如,如果a2
实际上是常量),这可能是合适的,但如果您不知道有多大{{1},通常应该避免}和a1
是。
您的第二个选项几乎计算相对差异,但有一个错误;它实际上应该是:
a2
(注意除法是里面的绝对值;否则,这个条件对于负fabs((a1-a2)/a2) < epsilon
)是无用的。对于大多数用途,相对误差更正确,因为它更接近于浮点舍入实际发生的方式,但是在某些情况下它不起作用并且您需要使用绝对容差(通常这是因为灾难性的取消)。您有时也会看到以这种形式写的相对错误界限:
a2
这通常会更有效率,因为它避免了分裂。
答案 4 :(得分:2)
Epsilon根据双范围内的值而变化。如果您想使用自己的和已修复 epsilon,我建议为1
选择一个epsilon。
fabs(a1-a2) < epsilon
这并不完美。如果a1
和a2
是来自小数字操作的结果,则epsilon会很小。如果a1
和a2
是来自大数字操作的结果,则epsilon会很大。
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)))));
}