提问人:Johnathan Gross 提问时间:10/12/2017 最后编辑:Johnathan Gross 更新时间:10/12/2017 访问量:4240
浮点值与 0.0 的比较
Comparison to 0.0 with floating point values
问:
使用浮点数时,有时会出现舍入问题。因此,通常不建议将计算结果与 == 或 != 进行比较,而是使用适当的边界,如 。abs(a-b)<1.0e-10
但是用它来比较是否合适?0.0
这就是我在说的:
double foo(){
//code which can return values that aren't 0.0
//all returns are either literals or global variables defined with literals
return 0.0;
}
这里将始终返回 exactly 或明确不是 的数字。具体而言,这些数字的量级均大于但小于 。f
0.0
0.0
0.1
2.0
如果它返回,将永远如此?是否有可能 if 返回的值不是 ?0.0==foo()
true
0.0
0.0==foo()
true
foo
0.0
答:
以你为安全。这是因为尾数是整数类型(通常是特定于平台的 uint;然后通过符号位和指数将其扩展为浮点数)。std::numeric_limits::digits<float>
http://en.cppreference.com/w/cpp/types/numeric_limits/digits
如果你返回一个文字,那么是的,但这通常不是一个好主意,因为虽然今天是这样,但你能确定在维护或代码重用下它会保持正确吗?最好编写一些可以在更广泛的环境中工作的东西。在这种情况下:0.0
foo() < 0.1
对于您指定的所有值,将返回 false。更通用的解决方案是测试是否足够接近零:
static const EPSILON = 0.00001 ;
std::fabs( foo() - 0.0 ) < EPSILON ;
最好使用上述模式之一,因为它不需要对“零”的精度做出任何保证。foo()
评论
foo()
在您的情况下,使用浮点相等是完全正确的。== 0.0
它完全符合函数的意图(如果失败,则返回某个值或 0.0)。使用任何其他 epsilon 在某种程度上是任意的,并且需要了解正确值的范围。如果有什么变化,那很可能是值的范围而不是 0,因此测试的未来证明并不比其他解决方案 IMO 差。== 0.0
我看到的唯一问题是一些编译器会警告相等(-Wfloat-equal)的可疑使用......这与警告一样有用,因为这样的指令可能会导致问题(整数溢出和未定义的行为)。奇怪的是,我从未看到第二个警告。int a,b,c; ...; c=a+b;
因此,如果你想使用 -Wall -Werror 编译器选项来证明未来,你可以以不同的方式对失败进行编码(例如使用负值)并测试 foo < 0.0 - 直到有人发现浮点不等式可能也需要容差并将构造声明为可疑。
评论
-0.0
std::optional
boost::optional