93

I know that the integer values 0 and -0 are essentially the same. But, I am wondering if it is possible to differentiate between them.

For example, how do I know if a variable was assigned -0?

bool IsNegative(int num)
{
    // How ?
}

int num = -0;
int additinon = 5;

num += (IsNegative(num)) ? -addition : addition;

Is the value -0 saved in the memory the exact same way as 0?

Marco A.
  • 43,032
  • 26
  • 132
  • 246
Filip Minx
  • 2,438
  • 1
  • 17
  • 32
  • 4
    Why dont you check the sign bit? – tema Apr 30 '15 at 08:24
  • 9
    For integers, there's no difference. – Maroun Apr 30 '15 at 08:25
  • 15
    This depends on the implementation, but for implementations where `int` is represented in 2's complement (by far the most commonly encountered), `0` and `-0` have identical bitwise representations. – Mankarse Apr 30 '15 at 08:25
  • 11
    On a 2's complement machine there's no difference at bit-level. – Marco A. Apr 30 '15 at 08:26
  • No, that is unreal. In binary -0 and 0 represents equally – VirtualSnake Apr 30 '15 at 08:26
  • No, it is not possible. There is no -0 ... that's why long range goes from −2,147,483,648 to 2,147,483,647 ... you might see, that the lower range has one no more, than the upper range. – Mr.Yellow Apr 30 '15 at 08:27
  • 18
    @VirtualSnake: What does "in binary" mean? There are, in fact, binary encodings for which there *is* a distinction between -0 and 0. Sign and magnitude, for example. – Benjamin Lindley Apr 30 '15 at 08:28
  • @BenjaminLindley Of course but we are taking about int – VirtualSnake Apr 30 '15 at 08:37
  • 8
    @VirtualSnake That's right, we're talking about `int`. See [Ones' complement encoding](https://en.wikipedia.org/wiki/Ones%27_complement). – CiaPan Apr 30 '15 at 09:29
  • 2
    If you'd be using floating point, there'd be a difference... But with integers in real life scenarios (2-s complement machines) there is no difference –  Apr 30 '15 at 11:00
  • 1
    *"the integer values 0 and -0 are essentially the same."* At least in math, they are exactly the same. Would you also expect different representations for `1` and `-(-1)`? (and another for `-(-(-(-1)))`, ...) – ypercubeᵀᴹ May 05 '15 at 23:45

7 Answers7

114

It depends on the machine you're targeting.

On a machine that uses a 2's complement representation for integers there's no difference at bit-level between 0 and -0 (they have the same representation)

If your machine used one's complement, you definitely could

0000 0000   -> signed   0 
1111 1111   -> signed   −0

Obviously we're talking about using native support, x86 series processors have native support for the two's complement representation of signed numbers. Using other representations is definitely possible but would probably be less efficient and require more instructions.

(As JerryCoffin also noted: even if one's complement has been considered mostly for historical reasons, signed magnitude representations are still fairly common and do have a separate representation for negative and positive zero)

Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • Can you tell how likely it is to have one's complement? Is it rather exotic and which machines have it? Is there an advantage of this representation or is it only less efficient? – TobiMcNamobi Apr 30 '15 at 08:42
  • 6
    @TobiMcNamobi: Not likely enough to ever be concerned about. I'd be surprised if anybody has ever bothered to port a C++ compiler to produce output for such a machine. – Benjamin Lindley Apr 30 '15 at 08:47
  • 1
    I agree with Benjamin, [historically](http://en.wikipedia.org/wiki/UNIVAC_1100/2200_series) there have been machines using it, but nowadays I don't happen to know production machines which use it. Nevertheless it is always good to know and to keep in mind. – Marco A. Apr 30 '15 at 08:48
  • 4
    @TobiMcNamobi one's complement is still in use in the UNISYS 2200 system http://stackoverflow.com/a/12277974/995714 http://stackoverflow.com/q/6971886/995714 – phuclv Apr 30 '15 at 09:12
  • 2
    I've never looked at the one's complement requirements -- does the standard actually guarantee that `0` and `-0` are *different*? I honestly would have expected it to behave more like allowing two bit representations of the same value, and your program can use whichever one it feels like. –  Apr 30 '15 at 12:36
  • 8
    @Hurkly: no, even if a negative zero representation exists, the standard doesn't guarantee that assignment or initialization using the expression `-0`, that is to say the result of applying the unary `-` operator to the integer constant `0`, is a negative zero representation. Regardless of representation, the standard never says `0` and `-0` are mathematically different values, only that there might be a negative-zero bit pattern. If there is, it still represents the same numeric value, 0. – Steve Jessop Apr 30 '15 at 12:49
  • @SteveJessop If the use of the C standard as a general normative reference means it applies here, then it in fact guarantees it is _not_ a negative zero. See my answer. – Random832 Apr 30 '15 at 17:57
  • Although you have answered about `-0` and `0`, the question was really about code that stores such a value into a variable. The question I have is, do compilers for signed-magnitude processors actually differentiate between value *representations* when doing optimizations (making it more complicated for cross-compilers)? Or will such compilers constant-propagate a `-0` at compile time and end up with a 0...0b bit-representation passed to `IsNegative`? What are the guarantees here, of the architecture and compiler? – Johannes Schaub - litb May 01 '15 at 14:38
  • Note that I am not so much interested in the C-Standard (which leaves it unspecified or implementation defined, not sure), but about the actual implementations guarantees. – Johannes Schaub - litb May 01 '15 at 14:40
15

For an int (in the almost-universal "2's complement" representation) the representations of 0 and -0 are the same. (They can be different for other number representations, eg. IEEE 754 floating point.)

RichieHindle
  • 272,464
  • 47
  • 358
  • 399
14

Let's begin with representing 0 in 2's complement (of course there exist many other systems and representations, here I'm referring this specific one), assuming 8-bit, zero is:

0000 0000

Now let's flip all the bits and add 1 to get the 2's complement:

1111 1111 (flip)
0000 0001 (add one)
---------
0000 0000

we got 0000 0000, and that's the representation of -0 as well.

But note that in 1's complement, signed 0 is 0000 0000, but -0 is 1111 1111.

Maroun
  • 94,125
  • 30
  • 188
  • 241
  • 2
    Can I know why the downvotes in order to improve my answer please? – Maroun Apr 30 '15 at 19:40
  • 1
    While most of the other answers are technically correct, your answer is practical, and provides an implementation. Good. – umlcat May 06 '15 at 15:18
9

I've decided to leave this answer up since C and C++ implementations are usually closely related, but in fact it doesn't defer to the C standard as I thought it did. The point remains that the C++ standard does not specify what happens for cases like these. It's also relevant that non-twos-complement representations are exceedingly rare in the real world, and that even where they do exist they often hide the difference in many cases rather than exposing it as something someone could easily expect to discover.


The behavior of negative zeros in the integer representations in which they exist is not as rigorously defined in the C++ standard as it is in the C standard. It does, however, cite the C standard (ISO/IEC 9899:1999) as a normative reference at the top level [1.2].

In the C standard [6.2.6.2], a negative zero can only be the result of bitwise operations, or operations where a negative zero is already present (for example, multiplying or dividing negative zero by a value, or adding a negative zero to zero) - applying the unary minus operator to a value of a normal zero, as in your example, is therefore guaranteed to result in a normal zero.

Even in the cases that can generate a negative zero, there is no guarantee that they will, even on a system that does support negative zero:

It is unspecified whether these cases actually generate a negative zero or a normal zero, and whether a negative zero becomes a normal zero when stored in an object.

Therefore, we can conclude: no, there is no reliable way to detect this case. Even if not for the fact that non-twos-complement representations are very uncommon in modern computer systems.

The C++ standard, for its part, makes no mention of the term "negative zero", and has very little discussion of the details of signed magnitude and one's complement representations, except to note [3.9.1 para 7] that they are allowed.

Random832
  • 37,415
  • 3
  • 44
  • 63
  • In general no, the fact that something is true/required in C *doesn't* necessarily mean it's true/required in C++. The fact that C is a normative reference means that C++ refers to the C standard for various things (mainly the contents of standard headers), but the definition of integer types isn't one of those things. However, the absence of a guaranteed way to produce a negative zero means that what you conclude is still true, there's no sure way to generate one using arithmetic even if the representation exists. – Steve Jessop Apr 30 '15 at 23:39
  • Then why does the C++ standard go into so much less detail on things like this? – Random832 Apr 30 '15 at 23:39
  • 1
    Personal taste, I think, if the number of people voting on the C++ standard can be considered "personal" :-) If it was going to defer to the C standard for the definitions, though, then it could do a proper job of it and contain *no* detail, as it does in some other cases. – Steve Jessop Apr 30 '15 at 23:40
  • Does "C++ is a general purpose programming language based on the C programming language as described in ISO/IEC 9899:1999 Programming languages — C (hereinafter referred to as the C standard)." [1.1 para 2] have any normative meaning? I thought that that was intended to generally incorporate the C standard for anything not specifically overridden by the C++ standard. – Random832 Apr 30 '15 at 23:42
  • @Random832 No. It's just a historical note (there's, for instance, no `_Bool` or `_Complex` or designated initializers or compound literals in C++). The C++ standard knows how to incorporate the C standard when it wants to - e.g., [basic.fundamental]/p3: "The signed and unsigned integer types shall satisfy the constraints given in the C standard, section 5.2.4.2.1." – T.C. May 01 '15 at 06:15
8

If your machine has distinct representations for -0 and +0, then memcmp will be able to distinguish them.

If padding bits are present, there might actually be multiple representations for values other than zero as well.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
5

In the C++ language specification, there is no such int as negative zero.

The only meaning those two words have is the unary operator - applied to 0, just as three plus five is just the binary operator + applied to 3 and 5.

If there were a distinct negative zero, two's complement (the most common representation of integers types) would be an insufficient representation for C++ implementations, as there is no way to represent two forms of zero.


In contrast, floating points (following IEEE) have separate positive and negative zeroes. They can be distinguished, for example, when dividing 1 by them. Positive zero produces positive infinity; negative zero produces negative infinity.


However, if there happen to be different memory representations of the int 0 (or any int, or any other value of any other type), you can use memcmp to discover that:

#include <string>

int main() {
    int a = ...
    int b = ...
    if (memcmp(&a, &b, sizeof(int))) {
        // a and b have different representations in memory
    }
}

Of course, if this did happen, outside of direct memory operations, the two values would still work in exactly the same way.

Paul Draper
  • 78,542
  • 46
  • 206
  • 285
  • 3
    Actually, the language not mandating its existence does not mean it mandates its absence. Hint: It mandates neither. – Deduplicator Apr 30 '15 at 19:54
  • 2
    @Deduplicator, sort of. By "in the C++ language", I mean, "in the C++ language *specification*". Since there is no mention of froobinators in the spec either, I could say "C++ does not have froobinators" without too much ambiguity. I thought that was clear, but I will improve it. – Paul Draper Apr 30 '15 at 20:36
  • 1
    The language spec does not mention unicorns either. – ypercubeᵀᴹ May 05 '15 at 23:26
3

To simplify i found it easier to visualize.

Type int(_32) is stored with 32 bits. 32 bits means 2^32 = 4294967296 unique values. Thus :

unsigned int data range is 0 to 4,294,967,295

In case of negative values it depends on how they are stored. In case

In case of One's complement value -0 exists.

Margus
  • 19,694
  • 14
  • 55
  • 103
  • 2
    I haven't downvoted but the platforms for which `int` is not stored in 32 bits are more popular then platforms with one's complement nowadays. – Maciej Piechotka May 01 '15 at 05:07