将浮点数与零进行比较
C++ FAQ lite "[29.17] 为什么我的浮点比较有效吗?" 推荐这种相等性测试:
The C++ FAQ lite "[29.17] Why doesn't my floating-point comparison work?" recommends this equality test:
#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
}
- 这是否正确,这意味着唯一等于零的数字是
+0
和-0
? - 在测试零或者更确切地说是像
|x| 这样的测试时,是否也应该使用此功能?<ε
?
更新
正如 Daniel Daranas 所指出的,该函数可能最好称为 isNearlyEqual
(这是我关心的情况).
As pointed out by Daniel Daranas the function should probably better be called isNearlyEqual
(which is the case I care about).
有人指出 "比较浮动点数",我想更突出地分享.
Someone pointed out "Comparing Floating Point Numbers", which I want to share more prominently.
推荐答案
你的观察是正确的.
如果 x == 0.0
,则 abs(x) * epsilon
为零,您正在测试 abs(y) <= 0.0代码>.
If x == 0.0
, then abs(x) * epsilon
is zero and you're testing whether abs(y) <= 0.0
.
如果 y == 0.0
那么你正在测试 abs(x) <= abs(x) * epsilon
这意味着 epsilon >=1
(不是)或 x == 0.0
.
If y == 0.0
then you're testing abs(x) <= abs(x) * epsilon
which means either epsilon >= 1
(it isn't) or x == 0.0
.
所以 is_equal(val, 0.0)
或 is_equal(0.0, val)
都是没有意义的,你可以说 val == 0.0代码>.如果您只想接受 exactly
+0.0
和 -0.0
.
So either is_equal(val, 0.0)
or is_equal(0.0, val)
would be pointless, and you could just say val == 0.0
. If you want to only accept exactly +0.0
and -0.0
.
在这种情况下,FAQ 的建议是有限的.没有一刀切"的浮点比较.您必须考虑变量的语义、可接受的值范围以及计算引入的误差幅度.甚至常见问题解答都提到了一个警告,说这个函数通常不是问题当 x 和 y 的大小明显大于 epsilon 时,但你的里程可能会有所不同".
The FAQ's recommendation in this case is of limited utility. There is no "one size fits all" floating-point comparison. You have to think about the semantics of your variables, the acceptable range of values, and the magnitude of error introduced by your computations. Even the FAQ mentions a caveat, saying this function is not usually a problem "when the magnitudes of x and y are significantly larger than epsilon, but your mileage may vary".
相关文章