1

This code snippet in Visual Studio 2013:

double a = 0.0;
double b = -0.0;

cout << (a == b) << " " << a << " " << b;

prints 1 0 -0. What is the difference between a and b?

Paul Jurczak
  • 7,008
  • 3
  • 47
  • 72
  • 5
    http://en.wikipedia.org/wiki/Signed_zero – Igor Tandetnik Aug 13 '14 at 03:28
  • 4
    The difference is either `0` or `-0` – M.M Aug 13 '14 at 03:29
  • Dear downvoters, I tried googling it, unfortunately my query `float -0 0` was treated too literally. `float "-0" 0` works much better. Just in case someone else itches to downvote. – Paul Jurczak Aug 13 '14 at 03:48
  • @MattMcNabb Thanks, I meant `a` and `b`. – Paul Jurczak Aug 13 '14 at 03:51
  • 2
    [*"floating point negative zero"*](https://www.google.com/search?q=floating+point+negative+zero) makes an even better search queue. The top hit is a Wikipedia article on [signed zero](http://en.wikipedia.org/wiki/Signed_zero), probably a good read. The matter is not limited to C++, much less Visual Studio. It is an IEEE standard for floating point values. – Cody Gray - on strike Aug 13 '14 at 04:02
  • Also related: [Does float have a negative zero? (-0f)](http://stackoverflow.com/questions/5095968/does-float-have-a-negative-zero-0f) – Cody Gray - on strike Aug 13 '14 at 04:03

2 Answers2

4

C++ does not guarantee to differentiate between +0 and -0. This is a feature of each particular number representation. The IEEE 754 standard for floating point arithmetic does make this distinction, which can be used to keep sign information even when numbers go to zero. std::numeric_limits does not directly tell you if you have possible signed zeroes. But if std::numeric_limits<double>::is_iec559 is true then you can in practice assume that you have IEEE 754 representation, and thus possibly negative zero.


Noted by “gmch” in a comment, the C++11 standard library way to check the sign of a zero is to use std::copysign, or more directly using std::signbit, e.g. as follows:

#include <iostream>
#include <math.h>       // copysign, signbit

using namespace std;

auto main() -> int
{
    double const z1 = +0.0;
    double const z2 = -0.0;

    cout << boolalpha;
    cout << "z1 is " << (signbit( z1 )? "negative" : "positive") << "." << endl;
    cout << "z2 is " << (signbit( z2 )? "negative" : "positive") << "." << endl;
}

Without copysign or signbit, e.g. for a C++03 compiler, one way to detect a negative zero z is to check whether 1.0/z is negative infinity, e.g. by checking if it's just negative.

#include <iostream>
using namespace std;

auto main() -> int
{
    double const z1 = +0.0;
    double const z2 = -0.0;

    cout << boolalpha;
    cout << "z1 is " << (1/z1 < 0? "negative" : "positive") << "." << endl;
    cout << "z2 is " << (1/z2 < 0? "negative" : "positive") << "." << endl;
}

But while this will probably work in practice on most any implementation, it's formally *Undefined Behavior.

One needs to be sure that the expression evaluation will not trap.


*) C++11 §5.6/4 “If the second operand of / or % is zero the behavior is undefined”

Community
  • 1
  • 1
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
2

See http://en.m.wikipedia.org/wiki/Signed_zero

In a nutshell, it is due to the sign being stored as a stand-alone bit in IEEE 754 floating point representation. This leads to being able to have a zero exponent and fractional portions but still have the sign bit set--thus a negative zero. This is a condition that wouldn't happen for signed integers which are stored in twos-complement.

ptdecker
  • 404
  • 3
  • 10
  • 3
    Signed integers may be stored in one's complement or sign-magnitude, which has negative zero. – M.M Aug 13 '14 at 03:38
  • @MattMcNabb is technically correct. You might see ones complement used on older mainframe and minis from three decades ago or so. There is some good history about it here: http://en.m.wikipedia.org/wiki/Signed_number_representations – ptdecker Aug 13 '14 at 03:47