Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Behaviour of negative zero (-0.0) in comparison with positive zero (+0.0)

In my code,

float f = -0.0; // Negative 

and compared with negative zero

f == -0.0f

result will be true.

But

float f = 0.0; // Positive

and compared with negative zero

f == -0.0f

also, result will be true instead of false

Why in both cases result to be true?


Here is 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;
    }
}

Output:

==== > -0  // Here print negative zero

true
like image 249
Jayesh Avatar asked Aug 21 '17 10:08

Jayesh


3 Answers

Floating point arithmetic in C++ is often IEEE-754. This norm differs from the mathematical definition of the real number set.

This norm defines two different representations for the value zero: positive zero and negative zero. It is also defined that those two representations must compare equals, so by definition:

+0.0 == -0.0

As to why it is so, in its paper What Every Computer Scientist Should Know About Floating Point Arithmetic, David Goldberg, 1991-03 (linked in the IEEE-754 page on the IEEE website) writes:

In IEEE arithmetic, it is natural to define log 0 = -∞ and log x to be a NaN when x < 0. Suppose that x represents a small negative number that has underflowed to zero. Thanks to signed zero, x will be negative, so log can return a NaN. However, if there were no signed zero, the log function could not distinguish an underflowed negative number from 0, and would therefore have to return -∞.

like image 149
YSC Avatar answered Oct 31 '22 10:10

YSC


C++11 introduced functions like std::signbit() which can detect signed zeros, and std::copysign() which can copy the sign bit between floating point values, if the implementation supports signed zero (e.g. due to using IEEE floating point). The specifications of those functions don't actually require that an implementation support distinct positive and negative zeros. That sort of thing aside, I'm unaware of any references in a C++ standard that even mentions signed zeros, let alone what should be the result of comparing them.

The C++ standards also do not stipulate any floating point representation - that is implementation-defined.

Although not definitive, these observations suggest that support of signed zeros, or the result of comparing them, would be determined by what floating point representation the implementation supports.

IEEE-754 is a common (albeit not the only) floating point representation used by modern implementations (i.e. compilers on their host systems). The current (published in 2008) version of IEEE-758 "IEEE Standard for Floating -Point Arithmetic" Section 5.11, second paragraph, says (bold emphasis mine)

Four mutually exclusive relations are possible: less than, equal, greater than, and unordered. The last case arises when at least one operand is NaN. Every NaN shall compare unordered with everything, including itself. Comparisons shall ignore the sign of zero (so +0 = −0). Infinite operands of the same sign shall compare equal.

like image 15
Peter Avatar answered Oct 31 '22 09:10

Peter


That's because the signed negative zero must compare true with zero: i.e. -0.0 == 0.0, -0f == 0f, and -0l == 0l.

It's a requirement of any floating point scheme supported by a C++ compiler.

(Note that most platforms these days use IEEE754 floating point, and this behaviour is explicitly documented in that specification.)

like image 12
Bathsheba Avatar answered Oct 31 '22 08:10

Bathsheba