Signed int -0 ?

  • Thread starter Christian Stigen Larsen
  • Start date
C

Christian Stigen Larsen

A signed int reserves one bit to signify whether a number is positive or
negative. In light of this, a colleague asked me whether there existed an
int in C++ that was -0, a zero with the negative bit set. I was intrigued
by this, so I tried the following code:

#include <stdio.h>

int main(int, char**) {
int a(-0);
printf("a=%d\n", a);
if ( a==0 ) printf("a==0\n");
if ( a==-0 ) printf("a==-0\n");
return 0;
}

The output is:

a=0
a==0
a==-0

So it seems that no such number can be used in C++, and speaking of
mathematical numbers, it makes perfect sense, but what is actually going on
"behing the curtains" in C++ since the compiled code can't discern between
+0 and -0 ?
 
R

Rolf Magnus

Christian said:
A signed int reserves one bit to signify whether a number is positive
or
negative. In light of this, a colleague asked me whether there
existed an
int in C++ that was -0, a zero with the negative bit set. I was
intrigued by this, so I tried the following code:

#include <stdio.h>

int main(int, char**) {
int a(-0);
printf("a=%d\n", a);
if ( a==0 ) printf("a==0\n");
if ( a==-0 ) printf("a==-0\n");
return 0;
}

The output is:

a=0
a==0
a==-0

So it seems that no such number can be used in C++, and speaking of
mathematical numbers, it makes perfect sense, but what is actually
going on "behing the curtains" in C++ since the compiled code can't
discern between +0 and -0 ?

Negative numbers are usually expressed as 2's complement, where e.g. an
8 bit number can represent values from -128 to +127, including onle one
possible value for 0. It's not just one sign bit that is different.

Btw: Somehow, but not totally unrelated, in floating point units, there
actually often is +0 and -0, so while e.g. 1-1 is 0, I think -1+1
results in -0. This can be useful in some calculations.
 
R

Ron Natalie

Christian Stigen Larsen said:
A signed int reserves one bit to signify whether a number is positive or
negative. In light of this, a colleague asked me whether there existed an
int in C++ that was -0, a zero with the negative bit set. I was intrigued
by this, so I tried the following code:
There are several singed integer representations that are possible. While
the positive numbers are all pretty straight forward binary (this is required
by the standard), the negatives can be handled in a number of ways.
Some of thse have the possiblity for a negative zero value. However, the
most common representation used today is called "two's complement".
Two's complement has no negative zero, but it does have one more
negative value available than positive. That is, an 8 bit twos complement
number goes from -128 to 127.
 
V

Victor Bazarov

Rolf Magnus said:
Negative numbers are usually expressed as 2's complement, where e.g. an
8 bit number can represent values from -128 to +127, including onle one
possible value for 0. It's not just one sign bit that is different.

Both signed magnitude representation and 1's complement (which are,
IIRC, also allowed) have -0.

Victor
 
T

tom_usenet

A signed int reserves one bit to signify whether a number is positive or
negative.

On the contrary, it doesn't do that for the most common
representation, 2s complement.

In light of this, a colleague asked me whether there existed an
int in C++ that was -0, a zero with the negative bit set. I was intrigued
by this, so I tried the following code:

#include <stdio.h>

int main(int, char**) {
int a(-0);
printf("a=%d\n", a);
if ( a==0 ) printf("a==0\n");
if ( a==-0 ) printf("a==-0\n");
return 0;
}

The output is:

a=0
a==0
a==-0

That is the required output, regardless of the integer representation
used. (0 == -0 must be true).
So it seems that no such number can be used in C++, and speaking of
mathematical numbers, it makes perfect sense, but what is actually going on
"behing the curtains" in C++ since the compiled code can't discern between
+0 and -0 ?

Read up on 2s complement. Even in a 1s complement implementation, the
for an 8-bit binary number the bit pattern 11111111 will compare equal
to 00000000, since 11111111 and 00000000 are both representations of
0. For sign magnitude representations, 10000000 == 000000000 will hold
true for the same reason.

Tom
 
M

MiniDisc_2k2

It all comes down to how the computer represents those negative numbers. It
does not exactly just reserve one bit as you say:

decimal binary (8-bit)
-3 11111101
-2 11111110
-1 11111111
0 00000000
1 00000001
2 00000010
3 00000011

Thus you can see why there can be no -0. With each increase, the number
increases by one. For further explanation, to convert a number to a
negative, all you do is reverse all the bits (take the one's complement) and
then add one (take the two's complement). Thus:

If we start with 0: 00000000
Take the one's complement: 11111111
Take the two's complement: 00000000 (drop the 1 off from the end)

You see we get the same number. Thus, no -0 exists.

-- MiniDisc_2k2
To reply, replace nospam.com with cox dot net.
 
R

Rolf Magnus

Victor said:
Both signed magnitude representation and 1's complement (which are,
IIRC, also allowed) have -0.

That's why I used the word "usually" instead of "always".
 
T

Thore B. Karlsen

A signed int reserves one bit to signify whether a number is positive or
negative. In light of this, a colleague asked me whether there existed an
int in C++ that was -0, a zero with the negative bit set. I was intrigued
by this, so I tried the following code:

#include <stdio.h>

int main(int, char**) {
int a(-0);
printf("a=%d\n", a);
if ( a==0 ) printf("a==0\n");
if ( a==-0 ) printf("a==-0\n");
return 0;
}

The output is:

a=0
a==0
a==-0

So it seems that no such number can be used in C++, and speaking of
mathematical numbers, it makes perfect sense, but what is actually going on
"behing the curtains" in C++ since the compiled code can't discern between
+0 and -0 ?

Search for "two's complement" and you'll see. It's not just as simple as
reserving a bit for the sign.
 
S

Suzanne Vogel

For readers who skim, I'll start with a question (instead of burying it
below):
*** Is there a C++ library function that prints binary representations
of numbers?

Continuing. Thanks for the explanations. I was wondering yesterday
whether -0 had a different bit representation from 0. I thought how
terrible it would be if -0 *did* have a different bit representation
from 0, and NULL were defined as -0, and someone wrote an if-test that
relied on NULL being 0.

e.g.,
#define NULL -0 // redefine the NULL macro
....
char* buf = (char*)malloc(sizeof(char)*N);
if (!buf) { // if NULL has a nonzero bit representation, this will fail!
exit(1);
}

I think we should rely on bit representations of things only when we
have to (e.g., low-level file processing) or when we're trying to make
programs run more efficiently (e.g., bit ops). And I stop here because I
haven't done much of either of these.

Below is a little program I wrote to print binary representations. Yeah,
most of us have probably written one of these. If a C++ library function
exists for this, I feel silly.

I thought that actually *printing* bit representations was necessary to
show that the bit representations of -0 and 0 differ, because C++ can do
typecasts behind your back (e.g., from -0 to 0? I didn't know and didn't
want to take a chance).

--Suzanne
------------------------------------------------------------------------------------
// File: BitRepresentationsMain.cpp

#include <iostream>

///////////////////////////////////////////////////////////////////////////////
// TYPEDEFS AND CONSTANTS
///////////////////////////////////////////////////////////////////////////////

const int NUM_BITS_PER_CHAR = 8;

///////////////////////////////////////////////////////////////////////////////
// UTILITY FUNCTIONS
///////////////////////////////////////////////////////////////////////////////

// Convert integer n to a null-terminated string of 0's and 1's
representing its
// binary representation.
template<class T>
char* toBinary(char* binary, T n)
{
// Advance the pointer all the way to the right.
long nbits = sizeof(T) * NUM_BITS_PER_CHAR;
binary += nbits;

// Append null.
*binary = '\0';
binary--;

// Write chars via the pointer.
for (int i=0; i < nbits; i++)
{
*binary = (n & 1)==1 ? '1' : '0';
n = n >> 1;
binary--;
}
binary++;
return binary;
}

///////////////////////////////////////////////////////////////////////////////
// MAIN
///////////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
char* binary = (char*)malloc(sizeof(long) * NUM_BITS_PER_CHAR + 1);

std::cout << "-0:\t" << toBinary<int>(binary, int(-0)) << "\n";
std::cout << "0:\t" << toBinary<int>(binary, int(0)) << "\n";
std::cout << "-0:\t" << toBinary<long>(binary, long(-0)) << "\n";
std::cout << "0:\t" << toBinary<long>(binary, long(0)) << "\n";
std::cout << "-0:\t" << toBinary<char>(binary, char(-0)) << "\n";
std::cout << "0:\t" << toBinary<char>(binary, char(0)) << "\n";

for (int i=-3; i<=3; i++)
{
std::cout << i << ":\t" << toBinary<int>(binary, int(i)) << "\n";
}

free(binary);

return EXIT_SUCCESS;
}
 
S

Suzanne Vogel

Thanks for the feedback.
Why do you think that would be a type conversion? Anyway, the compiler
may keep the bits as they are and just treat 0 and -0 as equal.

*Suppose* (this is hypothetical) there were different representations of
0 and -0 for longs but not for ints.

Consider the following (made-up example):

if (0 == -0)... // possibly convert one of these

To compare 0 and -0, they must have the same type. So in *this* made-up
case, -0 would be a long and 0 would be an int, so 0 would be converted
(converted, not cast) to a long.

Similarly to the following (real example):

if (float(0.0) == double(0.0))... // convert float(0.0) to a double

** Is this not right?
Better use std::numeric_limits<char>::digits from the <limits> header or
CHAR_BIT from <climits>.
Good idea.

** Doesn't that just give the number of base-10 digits? If so, I guess I
could take the log base-2 of that to get the number of base-2 digits.

Suzanne
 
V

Victor Bazarov

Suzanne Vogel said:
Thanks for the feedback.


*Suppose* (this is hypothetical) there were different representations of
0 and -0 for longs but not for ints.

Consider the following (made-up example):

if (0 == -0)... // possibly convert one of these

To compare 0 and -0, they must have the same type. So in *this* made-up
case, -0 would be a long

No, it wouldn't. See the explanation below.
and 0 would be an int, so 0 would be converted
(converted, not cast) to a long.

Similarly to the following (real example):

if (float(0.0) == double(0.0))... // convert float(0.0) to a double

** Is this not right?

No. Not according to the C++ grammar. In it the code "-0" is
not a literal but an expression. "0" is a literal. It has the
type 'int' and base 8 (because it begins with 0). It's an octal
literal, and since it can be represented by 'int', it is an 'int'.

Now, -0 is a constant expression which involves negation operator
and the integer expression. The result is calculated by the
compiler on the fly and is (you guessed it!) 0.

Good idea.

** Doesn't that just give the number of base-10 digits?

No. For those there is std::numeric_limits said:
If so, I guess I
could take the log base-2 of that to get the number of base-2 digits.

You don't need to.

Victor
 
M

MiniDisc_2k2

Suzanne Vogel said:
For readers who skim, I'll start with a question (instead of burying it
below):
*** Is there a C++ library function that prints binary representations
of numbers?

In a way, yes. You can ask C++ to convert the number to a string in binary
format and then print that string:

int a; // the variable you wish to represent in binary
format.
char* string = new char[50];
itoa(a, string, 2); // the 2 means binary
std::cout << string;
delete string;
 
V

Victor Bazarov

MiniDisc_2k2 said:
Suzanne Vogel said:
For readers who skim, I'll start with a question (instead of burying it
below):
*** Is there a C++ library function that prints binary representations
of numbers?

In a way, yes. You can ask C++ to convert the number to a string in binary
format and then print that string:

int a; // the variable you wish to represent in binary
format.
char* string = new char[50];
itoa(a, string, 2); // the 2 means binary

Where did you dig out that function? Neither Standard C, nor
Standard C++ library has 'itoa'.
 
J

Jack Klein

A signed int reserves one bit to signify whether a number is positive or
negative. In light of this, a colleague asked me whether there existed an
int in C++ that was -0, a zero with the negative bit set. I was intrigued
by this, so I tried the following code:

#include <stdio.h>

int main(int, char**) {
int a(-0);
printf("a=%d\n", a);
if ( a==0 ) printf("a==0\n");
if ( a==-0 ) printf("a==-0\n");
return 0;
}

The output is:

a=0
a==0
a==-0

So it seems that no such number can be used in C++, and speaking of
mathematical numbers, it makes perfect sense, but what is actually going on
"behing the curtains" in C++ since the compiled code can't discern between
+0 and -0 ?

There are three defined formats for the representation of negative
signed integer values. Two of them have the physical possibility of
representing -0, one does not. Of the two that can physically
represent -0, that might actually be a valid value, or it might be a
trap value that causes undefined behavior.

On implementations that support -0, if you could actually find one, it
is required to compare equal to ordinary 0.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
V

Victor Bazarov

Ron Natalie said:
Only in C99.

What is that supposed to mean? The representation of negative
integers is not language-specific, it's hardware-specific.
 
R

Ron Natalie

Victor Bazarov said:
What is that supposed to mean? The representation of negative
integers is not language-specific, it's hardware-specific.
C99 defines (well limits the allowable) integer formats to three (signed mag, 1's comp.,
and 2's comp.). There is NO such restriction in C++. Any encoding that meets the
requirement that the positive numbers share representation with the corresponding unsigned
type meets the requirement.
 
V

Victor Bazarov

Ron Natalie said:
C99 defines (well limits the allowable) integer formats to three (signed mag, 1's comp.,
and 2's comp.). There is NO such restriction in C++. Any encoding that meets the
requirement that the positive numbers share representation with the corresponding unsigned
type meets the requirement.

Would you say, then, that C99 is smarter about it or that C++
is more flexible about it? AFAIK, there are no other schemes
than the three mentioned in this thread...

Victor
 
R

Ron Natalie

Victor Bazarov said:
Would you say, then, that C99 is smarter about it or that C++
is more flexible about it? AFAIK, there are no other schemes
than the three mentioned in this thread...
Got me. I've never understood why they were suddenly enumerated
in C99. To my knowledge I've never worked on a signed-mag machine
and I haven't been near a 1's complement machine in over a decade.
 
A

Alexander Terekhov

Ron Natalie wrote:
[...]
Got me. I've never understood why they were suddenly enumerated
in C99. To my knowledge I've never worked on a signed-mag machine
and I haven't been near a 1's complement machine in over a decade.

How about offset binary (aka "Excess-K"), various BCD schemes, uhmm,
and "gray code"? ;-)

regards,
alexander.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top