在我的代码中,
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
答案 0 :(得分:12)
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 <1时,将log 0 =-∞和log x定义为NaN是很自然的。 0.假设x表示一个下溢到零的小负数。由于有符号零,x将为负数,因此log可以返回NaN。但是,如果没有符号零,则日志函数无法将下溢的负数与0区分开,因此必须返回-∞。
答案 1 :(得分:10)
这是因为签名的负零必须将true
与零进行比较:即-0.0 == 0.0
,-0f == 0f
和-0l == 0l
。
这是C ++编译器支持的任何浮点方案的要求。
(请注意,目前大多数平台都使用IEEE754浮点,并且该规范明确记录了此行为。)
答案 2 :(得分:5)
C ++ 11引入了std::signbit()
这样可以检测带符号零的函数,std::copysign()
可以复制浮点值之间的符号位,如果实现支持有符号零(例如由于使用IEEE)浮点)。抛开那种事情,我不知道C ++标准中的任何引用甚至提到了带符号的零,更不用说比较它们的结果了
C ++标准也没有规定任何浮点表示 - 即实现定义。
虽然不是决定性的,但这些观察结果表明,对签名零的支持或比较它们的结果将由实现(也称为编译器)支持的浮点表示确定。
IEEE-754是现代实现(即编译器)使用的最常见(尽管不是唯一)浮点表示。当前(2008年出版)版本的IEEE-758“IEEE标准浮点运算”第5.11节第二段说(大胆强调我的)
可能存在四种互斥关系:小于,等于,大于,无序。当至少一个操作数是NaN时,出现最后一种情况。每个NaN都应将无序与包括其自身在内的所有内容进行比较。 比较应忽略零的符号(所以+0 = -0)。相同符号的无限操作数应比较相等。
答案 3 :(得分:-3)
因为0.0f和-0.0f相同,零的负数为零