在我的代码中,
float f = -0.0; // Negative
并与负零相比
f == -0.0f
结果将是true
。
但
float f = 0.0; // Positive
并与负零相比
f == -0.0f
另外,结果将是true
而不是false
为什么在这两种情况下都是真的?
这是a MCVE to test it (live on coliru):
#include <iostream>
int main()
{
float f = -0.0;
std::cout<<"==== > " << f <<std::endl<<std::endl;
if(f == -0.0f)
{
std::cout<<"true"<<std::endl;
}
else
{
std::cout<<"false"<<std::endl;
}
}
输出:
==== > -0 // Here print negative zero
true
C ++中的浮点运算通常是IEEE-754。该范数与实数集的数学定义不同。
这个规范defines two different representations for the value zero: positive zero and negative zero。还定义了这两个表示必须比较等于,因此根据定义:
+0.0 == -0.0
至于为什么会这样,在其论文What Every Computer Scientist Should Know About Floating Point Arithmetic,David Goldberg,1991-03(链接在IEEE网站上的IEEE-754页面)中写道:
在IEEE算术中,当x <0时,将log 0 =-∞和log x定义为NaN是很自然的。假设x表示已经下溢到零的小负数。由于有符号零,x将为负数,因此log可以返回NaN。但是,如果没有符号零,则日志函数无法将下溢的负数与0区分开,因此必须返回-∞。
那是因为有符号的负零必须将true
与零进行比较:即-0.0 == 0.0
,-0f == 0f
和-0l == 0l
。
这是C ++编译器支持的任何浮点方案的要求。
(请注意,目前大多数平台都使用IEEE754浮点,并且该规范明确记录了此行为。)
C ++ 11引入了可以检测带符号零的std::signbit()
函数,以及可以在浮点值之间复制符号位的std::copysign()
,如果实现支持有符号零(例如由于使用IEEE浮点)。抛开那种事情,我不知道C ++标准中的任何引用甚至提到了带符号的零,更不用说比较它们的结果了
C ++标准也没有规定任何浮点表示 - 即实现定义。
虽然不是确定的,但这些观察结果表明,对签名零的支持或比较它们的结果将由实现(也称为编译器)支持的浮点表示确定。
IEEE-754是现代实现(即编译器)使用的最常见(尽管不是唯一的)浮点表示。当前(2008年出版)版本的IEEE-758“IEEE标准浮点运算”第5.11节第二段说(大胆强调我的)
四种相互排斥的关系是可能的:小于,等于,大于和无序。当至少一个操作数是NaN时,出现最后一种情况。每个NaN都应该将无序与包括其自身在内的所有东西进行比较。比较应忽略零的符号(所以+0 = -0)。相同符号的无限操作数应相等。
因为0.0f和-0.0f相同,零的负数为零