负零(-0.0)与正零(+0.0)相比的行为

时间:2017-08-21 10:58:53

标签: c++ floating-point ieee-754

在我的代码中,

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

4 个答案:

答案 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相同,零的负数为零