没有epsilon可以将浮点数与0.0进行比较吗?

for*_*818 15 c++ floating-point equality

我知道,为了比较两个浮点值,需要使用一些epsilon精度,因为它们并不精确.但是,我想知道是否有边缘情况,我不需要那个epsilon.

特别是,我想知道做这样的事情总是安全的:

double foo(double x){
    if (x < 0.0) return 0.0;
    else return somethingelse(x); // somethingelse(x) != 0.0
}

int main(){
   int x = -3.0;
   if (foo(x) == 0.0) { 
     std::cout << "^- is this comparison ok?" << std::endl; 
   }
}
Run Code Online (Sandbox Code Playgroud)

我知道有更好的方法可以编写foo(例如,另外返回一个标志),但我想知道一般情况下是否可以分配0.0给浮点变量然后将其与之比较0.0.

或者更一般,以下比较是否总是如此?

double x = 3.3;
double y = 3.3;
if (x == y) { std::cout << "is an epsilon required here?" << std::endl; }
Run Code Online (Sandbox Code Playgroud)

当我尝试它时,似乎工作,但可能是一个人不应该依赖它.

ala*_*ain 8

是的,在这个例子中,检查== 0.0. 这不是因为0.0它在任何方面都很特殊,而是因为您只分配一个值并在之后进行比较。您也可以将其设置为3.3并比较 for == 3.3,这也可以。您正在存储一个位模式,并针对完全相同的位模式进行比较,只要这些值没有被提升为另一种类型来进行比较。

然而,在数学上等于零的计算结果并不总是等于0.0


这个问答已经发展到还包括程序的不同部分由不同的编译器编译的情况。问题没有提到这一点,我的回答仅适用于所有相关部分使用相同编译器的情况。

C++ 11 标准,
§5.10相等运算符

6 如果两个操作数都是算术或枚举类型,则对两个操作数进行通常的算术转换;如果指定的关系为真,则每个运算符都应为真,如果为假,则为假。

关系没有进一步定义,因此我们必须使用“平等”的常见含义。

§2.13.4浮动文字

1 [...] 如果缩放值在其类型的可表示值范围内,则结果是可表示的缩放值,否则以实现定义的方式选择最接近缩放值的较大或较小的可表示值。[...]

当值不可表示时,编译器必须在转换文字时恰好在两个值之间进行选择。如果始终为相同的文字选择相同的值,则可以安全地比较诸如3.3, 之类的值,因为==表示“相等”。

  • @EricLeschinski 你有这个说法的参考吗? (3认同)
  • 你错了,0.0 以一种非常独特的方式很特别。这就是为什么你可以用它做一些你不能用浮点数做的事情。 (2认同)
  • 这不是 0.0 是否只能用一个位模式表示的问题,而是相关浮点标准关于比较浮点数的说法。如今,很难找到不遵循 IEEE-754 或其近似派生标准的机器,这保证了将 +0.0 与 -0.0 进行比较将得出“相等”。当然,如果你做类似`y = foo(x); z = 0.0; if (memcmp(&amp;y, &amp;z, sizeof(z)) == 0) { it_is_zero(); }`,那么你必须确保位模式匹配。 (2认同)
  • 0.0 的特殊之处在于它没有十进制或二进制的重复尾数。还有其他特殊的浮点值共享这些属性,即在十进制及其转换后的二进制中以 17 个单位精度终止尾数。浮点比较的危险在于从十进制到二进制的转换,而不是双等号部分。参考:https://www.youtube.com/watch?v=PZRI1IfStY0 零的特殊性在于尾数是否在十进制到二进制转换器切断其余部分之前终止。在第二次阅读你的答案时。你没有错。 (2认同)

Pet*_*ker 5

是的,如果你回来,0.0你可以将它与之比较0.0; 0可以完全表示为浮点值.如果你返回,3.3你必须要小心,因为3.3不能完全表示,所以从double到float的转换会产生不同的值.

  • @DavidSchwartz我认为这不是问题.但问题是两个零的比较是否真实.即使两个零都表示不同,情况也许如此. (6认同)
  • 问题不在于零是否可以准确表示,而是它是否可以表示*唯一*. (2认同)
  • 如果您要比较的值是*计算的结果*,那么*零* 完全可以表示完全没有帮助。因此,虽然在所示的特定示例中是安全的,但它通常并不安全。 (2认同)
  • @PeteBecker抱歉,我不同意.您有标准,例如C++标准.问这个标准是什么和不保证是完全合理的. (2认同)