Why does printf("%d", ~0) output -1? [duplicate] - c

This question already has answers here:
What does ~0 do?
(4 answers)
Closed 7 years ago.
Why does printf("%d", ~0); yield a value of -1? Shouldn't it be 1 since the ~ operator converts each 1-bit into a 0-bit and vice versa?
From what I understand is 0000 will be negated to 1111.

~ is a bitwise complement operator . 00000000 is flipped to 11111111.
If you take 2'scomplement of 1(00000001) what you get is 11111111 which is to represent -1 in binary.
Therefore the output is -1.

Try to see the hex part of it.
printf("%x", ~0);
It will print ffff which means it negates every bit so 0000000000000000 is converted to 1111111111111111.
As per logic, if first bit is 1 then it is treated as negative number.
hence -1.

In 32-bit machine 0 represent as
00000000000000000000000000000000
As when you apply biwise NOT(~) then it flip all bit then bit representation like be
11111111111111111111111111111111
which is -1 representation of 2s complement.

In C/C++, ~ is the bitwise complement operator. For any given bitwise-complementable object x, it'll flip all binary digits found in the raw representation of x. Thus, if an integer x is represent in binary as 0b00000000, it'll become 0x11111111.
BUT!!!!!
The answer is not always -1. What happens is that there are two ways to represent negative numbers in existence, namely one's complement, and two's complement.
One's complement
For any number x, -x is represented as the bitwise complement of x.
Two's complement
For any number x, -x is represented as one plus the bitwise complement of x.
The real world
Find me a (modern) system using one's complement and I give you a free cookie! The fact is that one's complement allows for such nonsenses as -0, and in fact, your code would render that on a one's complement machine.
BTW, as other answers have already posted, the actual printing (not internal representation) of a number may vary if it's casted (unsigneds just ignore the extra top bit and thus allow for twice range before overflowing).

%d takes signed integer
different variations of same input
Signed Value ~0 -1
UnSigned Value ~0 4294967295
Hex Value ~0 ffffffff
Hex Value ~0 FFFFFFFF
as you can see the signed bit is set and its nothing but 2's compliment of 1
as a rule
-ve of n = (~n) + 1;
complement of 5 is -6
and complement(5)+1 is -5

Related

Objective C Int to 2's Complement Conversion

I'm trying to convert my 16 bit integer to two's complement if it's negative.
At the moment, I'm using the One's complement operator. I figure I can use that, and then add 1 to the binary value to convert it to two's complement. However, I'm unable to do x = ~a + 1 because that just yields the integer value + 1.
If my process is correct, how can I add 1 to the binary integer? If not, what is the most appropriate way to convert a 16 bit integer to 2's complement in Objective-C?
A two's complement is a kind of representation of signed numbers, not a value or an operation. On nearly all modern computers two's complements are the standard representation of signed integers. (And it is one of three allowed representations of integers in the standard.)
Therefore if you have any signed integral number, it is represented in two's complement. I think you want to have "the" two's complement of a positive number. This is simply the negative value, if your machine uses two's complements for signed numbers.
int positiveValue = 5;
int twosComplement = -positiveValue;

Using bit mask to convert a signed integer into two's complement

I am given this code to convert a signed integer into two's complement but I don't understand how it really works, especially if the input is negative.
void convertB2T( int32_t num) {
uint8_t bInt[32];
int32_t mask = 0x01;
for (int position = 0; position < NUM_BITS; position++) {
bInt[position] = ( num & Mask) ? 1 : 0;
Mask = Mask << 1;
}
}
So my questions are:
num is an integer, Mask is a hex, so how does num & Mask work? Does C just convert num to binary representation and do the bitwise and? Also the output of Mask is an integer correct? So if this output is non-zero, it is treated as TRUE and if zero, FALSE, right?
How does this work if num is negative? I tried running the code and actually did not get a correct answer (all higher level bits are 1's).
This program basically extracts each bit of the number and puts it in a vector. So every bit becomes a vector element. It has nothing to do with two's complement conversion (although the resulting bit-vector will be in two's complement, as the internal representation of numbers is in two's complement).
The computer has no idea what hex means. Every value is stored in binary, because binary is the only thing computer understands. So, ,the "integer" and the hex values are converted to binary (the hex there is also an integer). On these binary representations that the computer uses, the binary operators are applied.
In order to understand what is happening with the result when num is negative, you need to understand that the result is basically the two's complement representation of num and you need to know how the two's complement representation works. Wikipedia is a good starting point.
To answer your questions
1.Yes num is integer represented in decimal format and mask is also integer represented in hex format.
Yes C compiler treats num and mask with their binary equivalents.
Say
num = 24; // binary value on 32 bit machine is 000000000000000000011000
mask = 0x01; // binary value on 32 bit machine is 000000000000000000000001
Yes compiler now performs & bitwise and the equivalent binary values.
Yes if output is nonzero, treated as true
If a number is negative, its represented in 2's complement form.
Basically your code is just storing binary equivalent of number into array. You are not representing in twos complement.
If MSB is 1 indicates number is negative. if a number is negative
num = -24; // represent binary value of 24
000000000000000000011000 -> apply 1's complement + 1 to this binary value
111111111111111111100111 -> 1's complement
+000000000000000000000001 -> add 1
------------------------
111111111111111111101000 -> -24 representation
------------------------

Right bit-shift giving wrong result, can someone explain

I'm right-shifting -109 by 5 bits, and I expect -3, because
-109 = -1101101 (binary)
shift right by 5 bits
-1101101 >>5 = -11 (binary) = -3
But, I am getting -4 instead.
Could someone explain what's wrong?
Code I used:
int16_t a = -109;
int16_t b = a >> 5;
printf("%d %d\n", a,b);
I used GCC on linux, and clang on osx, same result.
The thing is you are not considering negative numbers representation correctly. With right shifting, the type of shift (arithmetic or logical) depends on the type of the value being shifted. If you cast your value to an unsigned value, you might get what you are expecting:
int16_t b = ((unsigned int)a) >> 5;
You are using -109 (16 bits) in your example. 109 in bits is:
00000000 01101101
If you take's 109 2's complement you get:
11111111 10010011
Then, you are right shifting by 5 the number 11111111 10010011:
__int16_t a = -109;
__int16_t b = a >> 5; // arithmetic shifting
__int16_t c = ((__uint16_t)a) >> 5; // logical shifting
printf("%d %d %d\n", a,b,c);
Will yield:
-109 -4 2044
The result of right shifting a negative value is implementation defined behavior, from the C99 draft standard section 6.5.7 Bitwise shift operators paragraph 5 which says (emphasis mine going forward):
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type
or if E1 has a signed type and a nonnegative value, the value of the result is the integral
part of the quotient of E1 / 2E2. If E1 has a signed type and a negative value, the
resulting value is implementation-defined.
If we look at gcc C Implementation-defined behavior documents under the Integers section it says:
The results of some bitwise operations on signed integers (C90 6.3, C99 and C11 6.5).
Bitwise operators act on the representation of the value including both the sign and value bits, where the sign bit is considered immediately above the highest-value value bit. Signed ‘>>’ acts on negative numbers by sign extension.
That's pretty clear what's happening, when representing signed integers, negative integers have a property which is, sign extension, and the left most significant bit is the sign bit.
So, 1000 ... 0000 (32 bit) is the biggest negative number that you can represent, with 32 bits.
Because of this, when you have a negative number and you shift right, a thing called sign extension happens, which means that the left most significant bit is extended, in simple terms it means that, for a number like -109 this is what happens:
Before shifting you have (16bit):
1111 1111 1001 0011
Then you shift 5 bits right (after the pipe are the discarded bits):
1XXX X111 1111 1100 | 1 0011
The X's are the new spaces that appear in your integer bit representation, that due to the sign extension, are filled with 1's, which give you:
1111 1111 1111 1100 | 1 0011
So by shifting: -109 >> 5, you get -4 (1111 .... 1100) and not -3.
Confirming results with the 1's complement:
+3 = 0... 0000 0011
-3 = ~(0... 0000 0011) + 1 = 1... 1111 1100 + 1 = 1... 1111 1101
+4 = 0... 0000 0100
-4 = ~(0... 0000 0100) + 1 = 1... 1111 1011 + 1 = 1... 1111 1100
Note: Remember that the 1's complement is just like the 2's complement with the diference that you first must negate the bits of positive number and only then sum +1.
Pablo's answer is essentially correct, but there are two small bits (no pun intended!) that may help you see what's going on.
C (like pretty much every other language) uses what's called two's complement, which is simply a different way of representing negative numbers (it's used to avoid the problems that come up with other ways of handling negative numbers in binary with a fixed number of digits). There is a conversion process to turn a positive number in two's complement (which looks just like any other number in binary - except that the furthest most left bit must be 0 in a positive number; it's basically the sign place-holder) is reasonably simple computationally:
Take your number
00000000 01101101 (It has 0s padding it to the left because it's 16 bits. If it was long, it'd be padded with more zeros, etc.)
Flip the bits
11111111 10010010
Add one.
11111111 10010011.
This is the two's complement number that Pablo was referring to. It's how C holds -109, bitwise.
When you logically shift it to the right by five bits you would APPEAR to get
00000111 11111100.
This number is most definitely not -4. (It doesn't have a 1 in the first bit, so it's not negative, and it's way too large to be 4 in magnitude.) Why is C giving you negative 4 then?
The reason is basically that the ISO implementation for C doesn't specify how a given compiler needs to treat bit-shifting in negative numbers. GCC does what's called sign extension: the idea is to basically pad the left bits with 1s (if the initial number was negative before shifting), or 0s (if the initial number was positive before shifting).
So instead of the 5 zeros that happened in the above bit-shift, you instead get:
11111111 11111100. That number is in fact negative 4! (Which is what you were consistently getting as a result.)
To see that that is in fact -4, you can just convert it back to a positive number using the two's complement method again:
00000000 00000011 (bits flipped)
00000000 00000100 (add one).
That's four alright, so your original number (11111111 11111100) was -4.

Integer presentation in computer - C

Does C define binary representation of integer e.g. one's, two's complement... or is this
representation processor (computer or something else) dependent?
Exmple of code written in C:
short a = -5;
Where do I need to look to know wheter a is two's complement 1111 1111 1111 1011 or
signed bit representation 1000 0000 0000 0101?
C supports the following three representations for signed integers:
2's complement (the most common, you're rather unlikely to see others in practice)
1's complement
sign-and-magnitude
C also allows there to be some padding (non-value) bits in the representation, which is also something very uncommon in practice.
C does not define whether integers should be stored in memory as big endian or little endian or in some other byte order.
If you want to find out how exactly integers are represented on a specific platform, you need to analyze the underlying memory. Also, if -INT_MAX == INT_MIN + 1, you have a 2's complement representation, otherwise it's uncertain, which one of the three it is.
I think it's safe to assume these days that there are no padding bits and the representation is 2's complement.
It is platform dependent, same as little/big Endian.
Also the number size of certain types are platform dependent.
The representation of an integer is something platform(processor)-dependent. See Endianness.
Binary representation of integer is platform dependent, if platform follows little endian then integers then -ve no.s are stored as 2's complement.
a= -5;
b = 5;
printf("%d %d", a, b);
printf("\n%u %u", a, b);
will display,
-5 5
4294967291 5
signed short -5 is 0xFFFB. The sign + absolute value representation doesn't make sense.
Addition and substractions doesn't care about signed/unsigned type. If you add 0xFFFB and 0x0005 you'll get 0x0000. If you try 0x8005 + 0x0005 you'll get 0x800A, which would be according to your hypothesis -10 which is nonsense. The number is binary complement, but rather it is just -x = 2^16 - x (mod 2^16) for short number.

Clarification is needed on bitwise not (~) operator

Suppose you have the following C code.
unsigned char a = 1;
printf("%d\n", ~a); // prints -2
printf("%d\n", a); // prints 1
I am surprised to see -2 printed as a result of ~1 conversion:
The opposite of 0000 0001 is 1111 1110. That is anything but -2.
What am I missing here?
It is two's complement.
In two's complement representation, if a number x's most significant bit is 1, then the actual value would be −(~x + 1).
For instance,
0b11110000 = -(~0b1111 + 1) = -(15 + 1) = -16.
This is a natural representation of negative numbers, because
0000001 = 1
0000000 = 0
1111111 = -1 (wrap around)
1111110 = -2
1111101 = -3 etc.
See http://en.wikipedia.org/wiki/Two%27s_complement for detail.
BTW, to print an unsigned value, use the %hhu or %hhx format. See http://www.ideone.com/YafE3.
%d stands for signed decimal number, not unsigned. So your bit pattern, even though it is stored in an unsigned variable, is interpreted as a signed number.
See this Wikipedia entry on signed number representations for an understanding of the bit values. In particular see Two's complement.
One (mildly humorous) way to think of signed maths is to recognize that the most significant bit really represents an infinite number of bits above it. So in a 16-bit signed number, the most significant bit is 32768+65536+131072+262144+...etc. which is 32768*(1+2+4+8+...) Using the standard formula for a power series, (1+ X + X^2 + X^3 +...) = 1/(1-X), one discovers that (1+2+4+8+...) is -1, so the sum of all those bits is -32768.

Resources