由于浮点"近似"性质,两个不同的值集可能返回相同的值.
示例:
#include <iostream>
int main() {
std::cout.precision(100);
double a = 0.5;
double b = 0.5;
double c = 0.49999999999999994;
std::cout << a + b << std::endl; // output "exact" 1.0
std::cout << a + c << std::endl; // output "exact" 1.0
}
Run Code Online (Sandbox Code Playgroud)
但减法也有可能吗?我的意思是:是否有两组不同的值(保留一个值)返回0.0
?
即a - b = 0.0
和a - c = 0.0
,给出了一些套a,b
和a,c
用b != c
?
我了解到比较双重使用==
并不是明智的做法.但是我想知道检查双重是否已经初始化可能是危险的.例如,知道变量doubleVar如果已初始化则不能为零,这样做是否安全?
Foo::Foo(){
doubleVar = 0.0; // of type double
}
void Foo::Bar(){
if(doubleVar == 0){ // has been initialized?
//...
}else{
//...
}
}
Run Code Online (Sandbox Code Playgroud) 我知道有很多陷阱与使用等比较具有double
的,所以我对如何实现某个值的检查谨慎等于准确 0.0
。基本上,我想知道是否从未分配过值,或者是否有意为该值分配0.0
了文字。我不想知道它是否接近零(例如 - 0.0000000001
)。
所以我在使用val == 0.0
或类似的东西之间进行辩论:
bool isZero(double val)
{
if (val > std::numeric_limits<double>::min()) {
return false;
} else if (val < -std::numeric_limits<double>::min()) {
return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
这两种说法会有区别吗?我应该偏爱一个吗?我特别关注下溢场景,其中val == -0.0
.
谢谢
我应该将“从未分配”声明澄清为“默认初始化后从未分配”。
我知道这里有很多关于为什么浮点相等比较通常是一个坏主意的问题。我理解浮点表示问题、舍入问题、将浮点无声地提升为双精度、依赖位级别算术的危险等。但在我看来,这应该没问题,而且我发现的任何问题似乎都没有涵盖这一点:
static const float MARKER = -500.0f; // some value well outside the range of valid values
std::vector<float> some_floats = {MARKER, 0.5f, 100.0f, 9.5f, MARKER, 0.f};
for (size_t i = 0; i< some_floats.size(); ++i) {
if (some_floats[i] == MARKER) {
std::cout << i << std::endl;
} else {
// do some math
}
}
Run Code Online (Sandbox Code Playgroud)
输出如预期:
0
4
Run Code Online (Sandbox Code Playgroud)
如果我-Wfloat-equal
启用了(在 gcc 中,但在其他编译器中类似),它会将比较行标记为危险:
comparing floating point with == or != is unsafe
。这里几乎所有的答案都说不要使用 == 或 !=, period。但我不明白为什么这里有问题。我只设置该常量一次,然后在其他使用它的地方重复使用它,并且永远不会对该常量进行任何操作(例如算术)。我错过了什么吗?0.0f
即使没有设置为常数,又怎么样?