26

How does C represent negative integers?

Is it by two's complement representation or by using the MSB (most significant bit)?

-1 in hexadecimal is ffffffff.

So please clarify this for me.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1s2a3n4j5e6e7v
  • 1,243
  • 3
  • 15
  • 29
  • 1
    Of course machine dependent, though the reference lists - I believe - three variants. The byte order is relevant for the memory layout of numbers: for 4 bytes ABCD, DCBA, BADC: `(uint8_t*)intptr`. – Joop Eggen May 04 '16 at 14:12

4 Answers4

48

ISO C (C99 section 6.2.6.2/2 in this case but it carries forward to later iterations of the standard(a)) states that an implementation must choose one of three different representations for integral data types, two's complement, ones' complement or sign/magnitude (although it's incredibly likely that the two's complement implementations far outweigh the others).

In all those representations, positive numbers are identical, the only difference being the negative numbers.

To get the negative representation for a positive number, you:

  • invert all bits then add one for two's complement.
  • invert all bits for ones' complement.
  • invert just the sign bit for sign/magnitude.

You can see this in the table below:

number | two's complement    | ones' complement    | sign/magnitude
=======|=====================|=====================|====================
     5 | 0000 0000 0000 0101 | 0000 0000 0000 0101 | 0000 0000 0000 0101
    -5 | 1111 1111 1111 1011 | 1111 1111 1111 1010 | 1000 0000 0000 0101

Keep in mind that ISO doesn't mandate that all bits are used in the representation. They introduce the concept of a sign bit, value bits and padding bits. Now I've never actually seen an implementation with padding bits but, from the C99 rationale document, they have this explanation:

Suppose a machine uses a pair of 16-bit shorts (each with its own sign bit) to make up a 32-bit int and the sign bit of the lower short is ignored when used in this 32-bit int. Then, as a 32-bit signed int, there is a padding bit (in the middle of the 32 bits) that is ignored in determining the value of the 32-bit signed int. But, if this 32-bit item is treated as a 32-bit unsigned int, then that padding bit is visible to the user’s program. The C committee was told that there is a machine that works this way, and that is one reason that padding bits were added to C99.

I believe that machine they may have been referring to was the Datacraft 6024 (and it's successors from Harris Corp). In those machines, you had a 24-bit word used for the signed integer but, if you wanted the wider type, it strung two of them together as a 47-bit value with the sign bit of one of the words ignored:

+---------+-----------+--------+-----------+
| sign(1) | value(23) | pad(1) | value(23) |
+---------+-----------+--------+-----------+
\____________________/ \___________________/
      upper word            lower word

(a) Interestingly, given the scarcity of modern implementations that actually use the other two methods, there's been a push to have two's complement accepted as the one true method. This has gone quite a long way in the C++ standard (WG21 is the workgroup responsible for this) and is now apparently being considered for C as well (by WG14).

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Makes me wonder why the (seemingly) most complex variant, twos complement, is the most popular. Flipping a single bit (sign/magnitude) or just flipping all bits (ones complement) seems simpler. I guess the popularity of twos complement is not related to how it works but rather how popular the machine implementing is was made (for other technical or marketing reasons)? – Frerich Raabe Jan 15 '14 at 08:29
  • 2
    @FrerichRaabe Straight from wikipedia "Binary arithmetic won't work." Essentially, how would the adder know its negative vs positive. http://simple.wikipedia.org/wiki/Signed_number_representations – JR Smith Feb 27 '14 at 14:05
  • @JRSmith that page is a bit weak; there certainly have been 1's complement and sign-magnitude in the past. In fact IEC60559 floating point uses sign magnitude and arithmetic works just fine. – M.M Aug 03 '15 at 03:50
  • @FrerichRaabe: Two's-complement is simple and beautiful if you recognize that for any integers x and y and whole number N, when using a sane compiler, the bottom N bits of x+y, x-y, or x*y will not depend upon anything but the bottom N bits of x and y. – supercat May 05 '16 at 18:32
  • The `20` way a copy-paste error from the C99 rationale. I find it amusing that padding bits are permitted to be in the middle of value bits. The quoted text is kinda self contradicting, the padding bit was invisible for signed, but is visible for unsigned. What does that even mean. As far as C standard is concerned it is still a padding bit, and does not contribute to the value. Thoughts? – 2501 Nov 05 '16 at 17:49
  • @2501, I'm not sure where you're contending the contradiction is. It states that the sign bit of the lower short is not used in calculating the value of the signed int. I'll update the answer with some more info ... – paxdiablo Nov 06 '16 at 07:44
  • It says, with signed the padding bit is not used for value, this is ok, and as it should be. Then it says, with unsigned that padding bit is visible. It isn't clear what is meant by visible. Is it used in the value calculation or not? According to the standard it shouldn't because it is still a padding bit. Therefore, what is the text refering to with the word: visible? If it means that it *is* used in the calculation, then it is a contradiction, as it is refered to as a padding bit that is used in value calculation. The standards says padding bits are not used in value calculation. – 2501 Nov 06 '16 at 08:19
  • @2501, I think I understand now, it does indeed depend on the definition of visible - it appears to be a lack of clarity that *may* result in a contradiction. That's almost worthy of another question:-) – paxdiablo Nov 07 '16 at 01:29
12

C allows sign/magnitude, one's complement and two's complement representations of signed integers. Most typical hardware uses two's complement for integers and sign/magnitude for floating point (and yet another possibility -- a "bias" representation for the floating point exponent).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
8

-1 in hexadecimal is ffffffff. So please clarify me in this regard.

In two's complement (by far the most commonly used representation), each bit except the most significant bit (MSB), from right to left (increasing order of magnitude) has a value 2n where n increases from zero by one. The MSB has the value -2n.

So for example in an 8bit twos-complement integer, the MSB has the place value -27 (-128), so the binary number: 1111 11112 is equal to -128 + 0111 11112 = -128 + 127 = -1

One useful feature of two's complement is that a processor's ALU only requires an adder block to perform subtraction, by forming the two's complement of the right-hand operand. For example 10 - 6 is equivalent to 10 + (-6); in 8bit binary (for simplicity of explanation) this looks like:

   0000 1010
  +1111 1010
   ---------
[1]0000 0100  = 4 (decimal)

Where the [1] is the discarded carry bit. Another example; 10 - 11 == 10 + (-11):

   0000 1010
  +1111 0101
   ---------
   1111 1111  = -1 (decimal)

Another feature of two's complement is that it has a single value representing zero, whereas sign-magnitude and one's complement each have two; +0 and -0.

Clifford
  • 88,407
  • 13
  • 85
  • 165
1

For integral types it's usually two's complement (implementation specific). For floating point, there's a sign bit.

Nathan Fellman
  • 122,701
  • 101
  • 260
  • 319
JoshD
  • 12,490
  • 3
  • 42
  • 53