2

Suppose I have a signed char member num = 15 and I do num = ~num. Then, as per this post, we will get -16.

~(00001111) = (11110000)

But, if I consider the MSB as sign bit, shouldn't the answer be -112? How come this is resulting in -16? Why the second and third set bits from left are being ignored.

Can anyone please clarify.

EDIT I want more detailed explaination of why the following program resulted in -16 and not -112

#include<stdio.h>

int main()
{
    char num = 15;
    num = ~num;

    printf("%d\n", num);
    return 0;
}

I expected it as 1(1110000) = -(1110000) = -112

Community
  • 1
  • 1
Naveen
  • 7,944
  • 12
  • 78
  • 165
  • 2
    In 2's complement the other bits beside the sign bit have the same meaning in both positive and negative; `11110000` is `-128 + 64 + 32 + 16` giving `-16` – M.M Jun 12 '16 at 12:36
  • The "sign bit" is not the "minus bit". Consider that adding 16 to it (as a raw bit pattern, disregard any meaning) results in 0, therefore it must have been -16 to begin with. – harold Jun 12 '16 at 12:42
  • you are mixing 1's compliment and signed bits. you should do 2's compliment. – mssirvi Jun 12 '16 at 13:30

2 Answers2

3

~(00001111) = (11110000)

What you're doing is using the MSb (Most Significant bit) as a flag to decide to put a '-' sign, and then reading the rest of the bits normally. Instead, the MSb is a flag to do 2 things: put a '-' sign - and then NOT the value and add one (2's complement) - before printing out the rest of the bits.

This comes from the overflow/underflow nature of fixed-length bit values:

00000010 - 1 = 00000001 (2-1=1)
00000001 - 1 = 00000000 (1-1=0)
00000000 - 1 = 11111111 (0-1=-1)
John Burger
  • 3,662
  • 1
  • 13
  • 23
3

C allows for three different representations of signed integers, but the most common is "two's complement". However, I'll briefly discuss "one's complement" as well to illustrate how there is a relationship between them.

One's complement

One's complement integers are split into sign and value bits. To use the 8-bit representation of the integer 19 as an example:

S|64 32 16  8  4  2  1
0| 0  0  1  0  0  1  1 = 19

Using the bitwise complement operator ~ flips all of the bits of the integer, including the sign bit:

S|64 32 16  8  4  2  1
1| 1  1  0  1  1  0  0 = ~19

When the sign bit is set, the interpretation of 1 and 0 bits is reversed (0=on, 1=off), and the value is considered negative. This means the value above is:

-(16 + 2 + 1) = -19

Two's complement

Unlike one's complement, an integer is not divided into a sign bit and value bits. Instead, what is regarded as a sign bit adds -2^(b - 1) to the rest of the value, where b is the number of bits. To use the example of an 8-bit representation of ~19 again:

-128 64 32 16  8  4  2  1
   1  1  1  0  1  1  0  0 = ~19

  -128 + 64 + 32 + 8 + 4
= -128 + 108
= -(128 - 108)
= -20

The relationship between them

The value of -19 is 1 more than -20 arithmetically, and this follows a generic pattern in which any value of -n in two's complement is always one more than the value of ~n, meaning the following always holds true for a value n:

-n = ~n + 1
~n = -n - 1 = -(n + 1)

This means that you can simply look at the 5-bit value 15, negate it and subtract 1 to get ~15:

~15 = (-(15) - 1)
    = -16

-16 for a 5-bit value in two's complement is represented as:

-16 8 4 2 1
  1 0 0 0 0 = -16

Flipping the bits using the ~ operator yields the original value 15:

-16 8 4 2 1
  0 1 1 1 1 = ~(-16) = -(-16 + 1) = -(-15) = 15

Restrictions

I feel I should mention arithmetic overflow regarding two's complement. I'll use the example of a 2-bit signed integer to illustrate. There are 2^2=4 values for a 2-bit signed integer: -2, -1, 0, and 1. If you attempt to negate -2, it won't work:

-2 1
 1 0 = -2

Writing +2 in plain binary yields 1 0, the same as the representation of -2 above. Because of this, +2 is not possible for a 2-bit signed integer. Using the equations above also reveals the same issue:

// Flip the bits to obtain the value of ~(-2)
~(-2) = -(-2 + 1)
~(-2) = 1

// Substitute 1 in place of ~(-2) to find the result of -(-2)
-(-2) = ~(-2) + 1
-(-2) = 1 + 1
-(-2) = 2

While this makes sense mathematically, the fact is that 2 is outside the representable range of values (only -2, -1, 0, and 1 are allowed). That is, adding 1 to 01 (1) results in 10 (-2). There's no way to magically add an extra bit in hardware to yield a new sign bit position, so instead you get an arithmetic overflow.

In more general terms, you cannot negate an integer in which only the sign bit is set with a two's complement representation of signed integers. On the other hand, you cannot even represent a value like -2 in a 2-bit one's complement representation because you only have a sign bit, and the other bit represents the value 1; you can only represent the values -1, -0, +0, and +1 with one's complement.