-3

I was working on converting 60 to 2's complement. This is how I did:

60 to binary   00111100
1's compliment 11000011
2's compliment 11000100 (by adding 1 to the 1's compliment)

When I execute this in a program using the following piece of code

#define NUM 60
unsigned char c;
c=~NUM;
printf("%d",c);

it prints 195 not 196. Please explain the reason behind this? Also explain process of calculating (~) of any given number.

Krzysztof Wolny
  • 10,576
  • 4
  • 34
  • 46
angel
  • 13
  • 2
  • 5

4 Answers4

2

The expression ~NUM is not strictly portable. To calculate your ones complement, you could try subtracting from UCHAR_MAX instead, for example: c = UCHAR_MAX - NUM;. This will work portably because according to the standard, UCHAR_MAX is required to be a binary power minus one:

The value UCHAR_MAX shall equal 2CHAR_BIT - 1.


Don't forget to increment c afterwards, as in your final step on paper: c++.


You could safely perform the entire twos complement operation in one step, providing your underlying choice of representation is unsigned (which it should be, because the whole idea of twos complement is to represent signed integers on an unsigned group of bits): c = -NUM;. This is because negative numbers are converted to unsigned types using the following procedure also described within the C11 standard:

... if the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type.

In this case that repeatedly happens to be once: -60 + UCHAR_MAX + 1 == 196 when UCHAR_MAX == 255. If we were talking about a larger value, such as -32767 then multiple such additions would be required.

On that note, if you need to operate with numbers greater than 32768 for NUM, you'll want to think about different suffixes, for example #define NUM 32768L would be sufficient, and much larger than that #define NUM 2147483648LL.

autistic
  • 1
  • 3
  • 35
  • 80
  • Why is `~NUM` not portable? – harold Mar 21 '16 at 12:04
  • @harold `60` is an `int` expression so it has a sign, and [the description of the unary `~` operator](http://port70.net/~nsz/c/c11/n1570.html#6.5.3.3p4) doesn't make a distinction for ones' complement or two's complement systems. In other words, it's certain that `~60` will result in one value on a ones' complement system, and another on a two's complement system. Not to mention, [a signed integer might have padding bits](http://port70.net/~nsz/c/c11/n1570.html#6.2.6.2p5) and the operator doesn't specify whether those bits are flipped, possibly resulting in use of trap representations (UB). – autistic Mar 21 '16 at 12:17
  • 1
    @harold I don't know why I didn't cite [this](http://port70.net/~nsz/c/c11/n1570.html#6.5p4), instead, but it'll supplement the above explanation... – autistic Mar 21 '16 at 15:50
1

The operator ~ performs a logical not giving back the 1's complement, not the 2's complement.
To perform the 2's complement in C use the - unary minus. See the following example:

#define NUM 60
char c1 = ~NUM;    //1's complement
char c2 = -NUM;    //2's complement
printf("NUM=%d, 1's complement=%d, 2's complement=%d\n",NUM, c1, c2);

But the main point is that you cannot perform a 2's complement on an unsigned type, because by default the 2's complement is used to find the representation of the same negative number. I.e. 2 -2, 10 -10, 5 -5, etc.
Consider that the values you are looking for are the unsigned representation of the negative (2's complement) value. I.e. adding:

printf("2's complementunsigned representation=%d\n", (unsigned char)c2);

Will print 196, that is -60, read as an unsigned value.

Frankie_C
  • 4,764
  • 1
  • 13
  • 30
0

The symbol ~ calculates the 1's complement of the number. You just have to add 1 to the calculation.

c = ~NUM + 1;

Your description of the process of calculating the 1's complement is correct. To know more about it visit the wiki page on 1's complement.

Cheers!

Simanraj
  • 1
  • 1
0

The ~ gives you the one's complement. Use negate (-) to get the two's complement.

#include <stdio.h>

#define NUM0 0
#define NUM60 60

int main() {
   unsigned char b;
   unsigned char c;

   b = ~NUM0;
   c = -NUM0;

   printf( "b=%d c=%d", b, c );

   b = ~NUM60;
   c = -NUM60;

   printf( "b=%d c=%d", b, c );
}

outputs: b=255 c=0 b=195 c=196

T Johnson
  • 824
  • 1
  • 5
  • 10