Complementing binary numbers - c

When I complement 1 (~1), I get the output as -2. How is this done internally?
I first assumed that the bits are inverted, so 0001 becomes 1110 and then 1 is added to it, so it becomes 1111 which is stored, how is the number then retrieved?

Well, no. When you complement 1, you go just invert the bits:
1 == 0b00000001
~1 == 0b11111110
And that's -2 in two's complement, which is the way your computer internally represents negative numbers. See http://en.wikipedia.org/wiki/Two's_complement but here are some examples:
-1 == 0b11111111
-2 == 0b11111110
....
-128== 0b10000000
+127== 0b01111111
....
+2 == 0b00000010
+1 == 0b00000001
0 == 0b00000000

Whar do you mean "when I complement 1 (~1)," ? There is what is called Ones-complement, and there is what is called Twos-Complement. Twos-Complement is more common (it is used on most computers) as it allows negative numbers to be added and subtracted using the same algorithm as postive numbers.
Twos-Complement is created by taking the binary representation of the postive number and switching every bit from 1 to 0 and from 0 to 1, and then adding one
5 0000 0101
4 0000 0100
3 0000 0011
2 0000 0010
1 0000 0001
0 0000 0000
-1 1111 1111
-2 1111 1110
-3 1111 1101
-4 1111 1100
-5 1111 1011
etc.

Related

How does c language store int in memory?

#include <stdio.h>
#include <stdlib.h>
int main() {
int *p_x = (int *)malloc(1 * sizeof(int));
scanf("%d", p_x);
for (int i = 0; i < 4; i++) {
char *one_byte_slice = (((char *)(p_x)) + i);
printf("slice : %d , value : %d\n", i, *one_byte_slice);
}
return 0;
}
When I entered positive values they seems understandable to me but for negative I don't understand it well.
For *p_x = 127:
127
slice : 0 , value : 127
slice : 1 , value : 0
slice : 2 , value : 0
slice : 3 , value : 0
p_x ---> 0111 1111
0000 0000
0000 0000
0000 0000
For *p_x = 256:
256
slice : 0 , value : 0
slice : 1 , value : 1
slice : 2 , value : 0
slice : 3 , value : 0
p_x ---> 0000 0000
0000 0001
0000 0000
0000 0000
For *p_x = -20:
-20
slice : 0 , value : -20
slice : 1 , value : -1
slice : 2 , value : -1
slice : 3 , value : -1
p_x ---> 1001 0100
1000 0001
1000 0001
1000 0001
And for *p_x = -256:
-256
slice : 0 , value : 0
slice : 1 , value : -1
slice : 2 , value : -1
slice : 3 , value : -1
p_x ---> 0000 0000
1000 0001
1000 0001
1000 0001
So how is it stored in memory for fixed point numbers is is stored in 2's complement or other way?
This is called low-endian encoding. The individual bit slices of the integer are stored from least significative to most significative in the consecutive byte cells.
Your integer is represented in binary form as:
0000 0000 0000 0000 0000 0000 0111 1111
(where I have used a space to separate each group of four bits).
Each byte is stored from the least significant group of eight bits to the most, in growing byte addresses, starting from the right above:
Addr. Value.
0000: 0111 1111
0001: 0000 0000
0002: 0000 0000
0003: 0000 0000
There's another way to do it, which is called big-endian, which stores the bytes just in the reverse direction, and some machines do it:
(Big-endian)
Addr. Value.
0000: 0000 0000
0001: 0000 0000
0002: 0000 0000
0003: 0111 1111
There are other ways to do, but today's computers normally use one of these two.
In the case of negative numbers, the solution consists in thinking that negative numbers and positive numbers are so that adding and subtrating can be done withou having to use an alternate circuitry. So numbers are divided in two halves and the ones with the most significant bit represent the negative ones... so numbers are represented (I'll use only four bits for brevity):
1000: -8
1001: -7
1010: -6
1011: -5
1100: -4
1101: -3
1110: -2
1111: -1
0000: 0
0001: 1
0010: 2
0011: 3
0100: 4
0101: 5
0110: 6
0111: 7
With 32 bits the result is the same, but extended to 32 bits... this makes that all the small negative numbers have all the most significant bits equal to 1.
1000 0000 0000 0000: -2147483648
1000 0000 0000 0001: -2147483647
...
1111 1111 1111 1101: -3
1111 1111 1111 1110: -2
1111 1111 1111 1111: -1
0000 0000 0000 0000: 0
0000 0000 0000 0001: 1
...
0111 1111 1111 1100: 2147483644
0111 1111 1111 1101: 2147483645
0111 1111 1111 1110: 2147483646
0111 1111 1111 1111: 2147483647
in such a way that adding is jumping in the previous table downwards and subtracting going upwards. This is called two's complement encoding.
Yeah i think i got my answer.
#include <stdio.h>
#include <stdlib.h>
int main() {
int *p_x = (int *) malloc(1*sizeof(int));
scanf("%d",p_x);
for(int i=0;i<4;i++) {
unsigned char *one_byte_slice = ( ((unsigned char *)(p_x)) + i);
printf("slice : %d , value : %hhx\n",i,*one_byte_slice);
}
return 0;
}
When i tried %hhx and unsigned char * it's shows me 2's complement for negative values.
-1
slice : 0 , value : ff
slice : 1 , value : ff
slice : 2 , value : ff
slice : 3 , value : ff
p_x ---> 1111 1111
1111 1111
1111 1111
1111 1111
-3
slice : 0 , value : fd
slice : 1 , value : ff
slice : 2 , value : ff
slice : 3 , value : ff
p_x ---> 1111 1101
1111 1111
1111 1111
1111 1111
Yeah so conclusion is it's stored in 2's complement format.

Bitwise addition of opposite signs

int main(){
int a = 10, b = -2;
printf("\n %d \n",a^b);
return 0;
}
This program outputs -12. I could not understand how. Please explain.
0111 1110 -> 2's complement of -2
0000 1010 -> 10
---------
0111 0100
This no seems to be greater than -12 and is +ve. But how did I get the o/p as -12 ?
To find the two's complement of a negative integer, first find the binary representation of its magnitude. Then flip all its bits, i.e., apply the bitwise NOT operator !. Then add 1 to it. Therefore, we have
2 --> 0000 0000 0000 0010
~2 --> 1111 1111 1111 1101 // flip all the bits
~2 + 1 --> 1111 1111 1111 1110 // add 1
Therefore, the binary representation of -2 in two's complement is
1111 1111 1111 1110
Now, assuming the size of int is 4, the representation of a and b in two's complement is -
a --> 0000 0000 0000 1010 --> 10
b --> 1111 1111 1111 1110 --> -2
a^b --> 1111 1111 1111 0100 --> -12
The operator ^ is the bitwise XOR, or exclusive OR operator. If operates on the corresponding bits of a and b and evaluates to 1 only when the bits are not both 0 or both 1, else it evaluate to 0.
Seems legit!
1111 1110 (-2)
xor
0000 1010 (10)
=
1111 0100 (-12)
^ is the bitwise XOR, not power
a = 10 = 0000 1010
b = -2 = 1111 1110
──────────────────
a^b = 1111 0100 = -12
(int) -2 = 0xfffffffe
(int) 10 = 0x0000000a
0xfffffffe ^ 0x0000000a = fffffff4 = (int) -12

C - data type conversion without computer

I have a sample question from test from my school. Which way is the most simple for solving it on paper?
The question:
Run-time system uses two's complement for representation of integers. Data type int has size 32 bits, data type short has size 16 bits. What does printf show? (The answer is ffffe43c)
short int x = -0x1bc4; /* !!! short */
printf ( "%x", x );
lets make it in two steps: 1bc4 = 1bc3 + 1
first of all we make this on long:
0 - 1 = ffffffff
then
ffffffff - 1bc3
this can be done by symbols
ffffffff
-
00001bc3
you will get the result you have
Since your x is negative take the two's complement of it which will yield:
2's(-x) = ~(x) + 1
2's(-0x1BC4) = ~(0x1BC4) + 1 => 0xE43C
0x1BC4 = 0001 1011 1100 0100
~0X1BC4 =1110 0100 0011 1011
+1 = [1]110 0100 0011 1100 (brackets around MSB)
which is how your number is represented internally.
Now %x expects a 32-bit integer so your computer will sign-extend your value which copies the MSB to the upper 16 bits of your value which will yield:
1111 1111 1111 1111 1110 0100 0011 1100 == 0xFFFFE43C

Why is ~0xF equal to 0xFFFFFFF0 on a 32-bit machine?

Why is ~0xF equal to 0xFFFFFFF0?
Also, how is ~0xF && 0x01 = 1? Maybe I don't get 0x01 either.
Question 1
Why is ~0xF equal to 0xFFFFFFF0?
First, this means you run this on a 32-bit machine. That means 0xF is actually 0x0000000F in hexadecimal,
And that means 0xF is
0000 0000 0000 0000 0000 0000 0000 1111 in binary representation.
The ~ operator means the NOT operation. Tt changes every 0 to 1 and every 1 to 0 in the binary representation. That would make ~0xF to be:
1111 1111 1111 1111 1111 1111 1111 0000 in binary representation.
And that is actually 0xFFFFFFF0.
Note that if you do this on a 16-bit machine, the answer of ~0xF would be 0xFFF0.
Question 2
You wrote the wrong statement, it should be 0xF & 0x1. Note that 0x1 0x01, 0x001, and 0x0001 are all the same. So let’s change this hexdecimal number to binary representation:
0xF would be:
0000 0000 0000 0000 0000 0000 0000 1111
and 0x1 would be:
0000 0000 0000 0000 0000 0000 0000 0001
The & operation follows the following rules:
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
So doing that to every bit, you get the result:
0000 0000 0000 0000 0000 0000 0000 0001
which is actually 0x1.
Additional
| means bitwise OR operation. It follows:
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
^ means bitwise XOR operation. It follows:
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
You can get more information here.
If you store 0xF in a 32-bit "int", all 32 bits flip, so ~0xF = 0xFFFFFFF0.
See this:
http://teaching.idallen.com/cst8214/08w/notes/bit_operations.txt
They give a good explanation
You're negating 0xF, which flips all of the bits to their inverse. So for example, with 8 bits you have: 0xF = 00001111. If you Negate that, it turns into 11110000.
Since you're using 32 bits, the F's are just extended all the way out. 1111 .... 0000
For your second question, you're using a logical AND, not a bitwise AND. Those two behave entirely differently.
It sounds like your confusion is that you believe 0xF is the same as 0b1111111111111111. It is not, it is 0b0000000000001111.
~0xF inverts all its bits, going
from 0x0000000F = 00000000000000000000000000001111 (32 bits)
to 0xFFFFFFF0 = 11111111111111111111111111110000 (32 bits)
a && b is 1 if both a and b are non-zero, and ~0xF and 0x01 are both non-zero.
In C, ~0xF can never be equal to 0xFFFFFFF0. The former is a negative number (in any of the three signed representations C allows) and the latter is a positive number. However, if both are converted to a 32-bit unsigned type on a twos-complement implementation, the converted values will be equal.
As for ~0xF && 0x01, the && operator is logical and, not bitwise and.

Please explain output

#include<stdio.h>
int main(void)
{
int a=-3,b=5,c;
c=a|b;
printf("%d ",c);
c=a&b;
printf("%d ",c);
}
The output is -3 5, please explain how?
To understand the output, you need to become familiar with the Two's Complement which is used to represent negative binary numbers. The conversion from +x to -x is actually quite easy: Complement all bits and add one.
Now just assume your ints are of length 8 bits (which is sufficient to examine 5 and -3):
5: 0000 0101
3: 0000 0011 => -3: 1111 1101
Now lets take a look at the bitwise or:
1111 1101 | 0000 0101 = 1111 1101
Exactly the represantation of -3
And now the bitwise AND:
1111 1101 & 0000 0101 = 0000 0101
Exactly the binary representation of 5
It helps when you look at the binary representations alongside each other:
-3 == 1111 1111 1111 1101
+5 == 0000 0000 0000 0101
The thing to understand is that both | and & will leave a bit alone if it has the same value on both sides. If the values are different (ie one operand has a 0 at that position and the other has a 1), then one of them "wins", depending on whether you're using | or &.
When you OR those bits together, the 1s win. However, the 5 has a 0 in the same position as the 0 in -3, so that bit comes through the OR operation unchanged. The result (1111 1111 1111 1101) is still the same as -3.
When you do a bitwise AND, the zeroes win. However, the 1s in 5 match up with 1s in -3, so those bits come through the AND operation unchanged. The result is still 5.
Binary of 5 --is--> 0000 0101
3 --> 0000 0011 -- 1's Complement --> 1111 1100 -- 2's Complement (add 1) --> 1111 1101 == -3. This is how it gets stored in Memory.
Bitwise OR Truth Table:
p OR q
p || q || p | q
T(1) || T(1) || T(1)
T(1) || F(0) || T(1)
F(0) || T(1) || T(1)
F(0) || F(0) || F(0)
1111 1101 | 0000 0101 = 1111 1101 == -3
Bitwise AND Truth Table:
p AND q
p || q || p & q
T(1) || T(1) || T(1)
T(1) || F(0) || F(0)
F(0) || T(1) || F(0)
F(0) || F(0) || F(0)
1111 1101 & 0000 0101 = 0000 0101 == 5
Also, see - What Every Computer Scientist Should Know About Floating-Point Arithmetic.
Get some paper and a writing implement of your choice
Write out -3 and 5 in binary ( See twos complement for how to do negative numbers)
hint: | means OR, & means AND
-3 = 0xFFFD = 1111 1111 1111 1101 5 = 0101 so the bitwise or does not change the first argument ( just overlap one with ones ) and results is still -3
The bitwise and takes the coomon ones between 1101 and 0101 that is 0101=5 :) no reason to consider all the trailing one in -3 since 5 = 0000 0000 0000 0101
If you know all about 2's complements, then you should know
how to write out 3 and 5 in 2's complement as bit31 bit32 ... bit3n and bit51 bit52 .. bit5n
how to compute the result of bit3i | bit5i for i = 0 ... n
how to convert the result back to base 10
That should give you your answer for the first, do the same with & for the second.
Ever hear of DeMorgan's law...??? The hint is in the linky, it is the table that epitomises and embodies the raw cold truth of logic that is pinned into the syntaxes of major language compilers...
Even more worrying is the fact that you don't have the basic CS101 knowledge and posting this question (Sorry if you take this to be condescending but am not), I genuinely cannot believe you're looking at a C code and not told anything about two's complements, bitwise logic... something is very wrong here... If your college lecturer has not told you any of it, said lecturer should not be lecturing at all and find another job.... sigh

Resources