一般单元测试中的浮点数比较
Floating point comparison in general unit tests
我知道这个问题已经讨论了很多。我在网上搜索并自己想出了一个算法。我想知道它是否可以作为在一般单元测试(而不是一些 serious/professional 数字测试)中正常工作的默认实现。
bool equal_to(double x, double y) {
using limits = std::numeric_limits<double>;
auto mag_x = std::abs(x);
auto mag_y = std::abs(y);
if (mag_x < mag_y) {
std::swap(x, y);
std::swap(mag_x, mag_y);
}
auto eps = limits::epsilon() * mag_x;
auto lb = x - eps;
auto ub = x + eps;
return lb < y && y < ub;
}
刚发现一个漏洞。最后一条语句应该是
return (x == y) || (lb < y && y < ub);
万一equal_to(0, 0);
不,这还不够。您的 eps
太低,可能应该乘以用于生成 x
和 y
的步骤数(尽管这些错误 经常 取消,这不能保证。
此外,您的舍入效果可能会因灾难性取消而放大。如果 x
大约为 0.1,因为它是按 10.0 - 9.9
计算的,那么您应该使用 limits::epsilon * (10+9.9)
。你太乐观了大约 100 倍。
我知道这个问题已经讨论了很多。我在网上搜索并自己想出了一个算法。我想知道它是否可以作为在一般单元测试(而不是一些 serious/professional 数字测试)中正常工作的默认实现。
bool equal_to(double x, double y) {
using limits = std::numeric_limits<double>;
auto mag_x = std::abs(x);
auto mag_y = std::abs(y);
if (mag_x < mag_y) {
std::swap(x, y);
std::swap(mag_x, mag_y);
}
auto eps = limits::epsilon() * mag_x;
auto lb = x - eps;
auto ub = x + eps;
return lb < y && y < ub;
}
刚发现一个漏洞。最后一条语句应该是
return (x == y) || (lb < y && y < ub);
万一equal_to(0, 0);
不,这还不够。您的 eps
太低,可能应该乘以用于生成 x
和 y
的步骤数(尽管这些错误 经常 取消,这不能保证。
此外,您的舍入效果可能会因灾难性取消而放大。如果 x
大约为 0.1,因为它是按 10.0 - 9.9
计算的,那么您应该使用 limits::epsilon * (10+9.9)
。你太乐观了大约 100 倍。