Bit By Bit
1. Convert following binary numbers into decimal numbers
1. 1111
Answer: 15
1 x 23 + 1 x 22 + 1 x 21 + 1 x 20 = 8 + 4 + 2 + 1 = 15
2. 1111 0000
Answer: 240
1 x 27 + 1 x 26 + 1 x 25 + 1 x 24 + 0 x 23 + 0 x 22 + 0 x 21 + 0 x 20
128 + 64 + 32 + 16 + 0 + 0 + 0 + 0 = 240
3. 1010 1011
Answer: 171
1 x 27 + 0 x 26 + 1 x 25 + 0 x 24 + 1 x 23 + 0 x 22 + 1 x 21 + 1 x 20
128 + 0 + 32 + 0 + 8 + 0 + 2 + 1 = 171
4. 1000 1000
Answer: 136
1 x 27 + 0 x 26 + 0 x 25 + 0 x 24 + 1 x 23 + 0 x 22 + 0 x 21 + 0 x 20
128 + 0 + 0 + 0 + 8 + 0 + 0 + 0 = 136
5. 1000
Answer: 8
1 x 23 + 0 x 22 + 0 x 21 + 0 x 20 = 8 + 0 + 0 + 0 = 8
6. 100
Answer: 4
1 x 22 + 0 x 21 + 0 x 20 = 4 + 0 + 0 = 4
7. 10
Answer: 2
1 x 21 + 0 x 20 = 2 + 0 = 2
8. 1
Answer: 1
1 x 20 = 1 = 1
2. What is the highest number that can be stored in 8 bits?
Answer: 255.
1111 1111 is the highest that can be stored.
1 x 27 + 1 x 26 + 1 x 25 + 1 x 24 + 1 x 23 + 1 x 22 + 1 x 21 + 1 x 20
128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 255
Alternately, the max number that can be stored can be calculated by
2n – 1, where n is the number of bits
Hence in 8 bits it will be 28 – 1 = 256 – 1 = 255
3. What is the highest number that can be stored in 9 bits?
Answer: 511
1 1111 1111 is the highest that can be stored.
1 x 28 + 1 x 27 + 1 x 26 + 1 x 25 + 1 x 24 + 1 x 23 + 1 x 22 + 1 x 21 + 1 x 20
256 + 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = 511
Alternately,
29 – 1 = 512 – 1 = 511
4. Convert following binary numbers into hexadecimal
1. 1101111100
Can be grouped into
11 0111 1100
From the table
0011 -> 3
0111 -> 7
1100 -> C
The hex notation will be
0x37C
2. 100000010000100
Can be grouped into
100 0000 1000 0100
From the table
0100 -> 4
0000 -> 0
1000 -> 8
0100 -> 4
The hex notation will be
0x4084
3. 11001100
Can be grouped into
1100 1100
From the table
1100 -> C
1100 -> C
The hex notation will be
0xCC
4. 1101001
Can be grouped into
110 1001
From the table
0110 -> 6
1001 -> 9
The hex notation will be
0x69
5. Convert following hexadecimal numbers into decimal and binary
1. 0xFF
1111 1111
15 x 161 + 15 x 160 = 240 + 15 = 255
2. 0xFF FF
1111 1111 1111 1111
15 x 163 + 15 x 162 + 15 x 161 + 15 x 160 = 61440 + 3840 + 240 + 15 = 65535
3. 0x10
0001 0000
1 x 161 + 0 x 160 = 16 + 0 = 16
4. 0xF0 00
1111 0000 0000 0000
15 x 163 + 0 x 162 + 0 x 161 + 0 x 160 =
61440 + 0 + 0 + 0 = 61440
6. Convert following decimal numbers into binary and hexadecimal
1. 128
Number | Step | Quotient | Remainder |
128 | Divide by 2 | 64 | 0 |
64 | Divide by 2 | 32 | 0 |
32 | Divide by 2 | 16 | 0 |
16 | Divide by 2 | 8 | 0 |
8 | Divide by 2 | 4 | 0 |
4 | Divide by 2 | 2 | 0 |
2 | Divide by 2 | 1 | 0 |
1 | Divide by 2 | 0 | 1 |
Binary: 1000 0000
Hex: 0x80
2. 15
Number | Step | Quotient | Remainder |
15 | Divide by 2 | 7 | 1 |
7 | Divide by 2 | 3 | 1 |
3 | Divide by 2 | 1 | 1 |
1 | Divide by 2 | 0 | 1 |
Binary: 1111
Hex: 0xF
3. 10
Number | Step | Quotient | Remainder |
10 | Divide by 2 | 5 | 0 |
5 | Divide by 2 | 2 | 1 |
2 | Divide by 2 | 1 | 0 |
1 | Divide by 2 | 0 | 1 |
Binary: 1010
Hex: 0xA
4. 40
Number | Step | Quotient | Reminder |
40 | Divide by 2 | 20 | 0 |
20 | Divide by 2 | 10 | 0 |
10 | Divide by 2 | 5 | 0 |
5 | Divide by 2 | 2 | 1 |
2 | Divide by 2 | 1 | 0 |
1 | Divide by 2 | 0 | 1 |
Binary: 10 1000
Hex: 0x28
5. 127
Number | Step | Quotient | Reminder |
127 | Divide by 2 | 63 | 1 |
63 | Divide by 2 | 31 | 1 |
31 | Divide by 2 | 15 | 1 |
15 | Divide by 2 | 7 | 1 |
7 | Divide by 2 | 3 | 1 |
3 | Divide by 2 | 1 | 1 |
1 | Divide by 2 | 0 | 1 |
Binary: 111 1111
Hex: 0x7F
7. What is the result of following operations
1. 0x3B & 0xF0
0x3B | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 |
0xF0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
& | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
Answer: 0x30
2. 0xFF & 0x01
0xFF | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
0x01 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
& | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Answer: 0x01
3. 0xFF & 0x00
0xFF | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
0x00 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
& | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Answer: 0x00
4. 0X87 & 0x78
0x87 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
0x78 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
& | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Answer: 0x00
8. What would be the output of following program. Note %x prints integer as hexadecimal value.
#include <stdio.h> int main(int argc, char * argv[]) { int operand1 = 0x42; int operand2 = 0x32; printf("0x%x & 0x%x = 0x%x \n", operand1, operand2, operand1&operand2); return 0; }
Ans:
& operation on 0x42 and 0x32
0x42 | 0 | 1 | 0 | 0 | 0 | 0 | 1 | 0 |
0x32 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 |
& | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Result is 0x02
The output of the program will be:
0x42 & 0x32 = 0x2
9. Explain the output of following program.
#include <stdio.h> int main(int argc, char * argv[]) { int operand1 = 0x42; int operand2 = 0x32; printf("0x%x & 0x%x = 0x%x \n", operand1, operand2, operand1&operand2); printf("%u %u %u\n",sizeof(operand1), sizeof(operand2),sizeof(operand1&operand2)); return 0; }
Ans:
0x42 & 0x32 = 0x2
4 4 4
The first row of output is explained in previous question.
Second row prints size of int three times, once each for operand1 and operand2 and once for the result of & operation. Since result of & of two ints is an int, we see same value printed thrice.
10. What is the result of following operations
1. 0x3B | 0xF0
0x3B | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 |
0xF0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
| | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 |
Answer: 0xFB
2. 0xFF | 0x01
0xFF | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
0x01 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Answer: 0xFF
3. 0xFF | 0x00
0xFF | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
0x00 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Answer: 0xFF
4. 0X87 | 0x78
0x87 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
0x78 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
| | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Answer: 0xFF
11. Explain the output of following program.
#include <stdio.h> int main(int argc, char * argv[]) { long operand1 = 0x100042; int operand2 = 0x2; printf("0x%lx | 0x%x = 0x%x \n", operand1, operand2, operand1|operand2); printf("%u %u %u\n",sizeof(operand1), sizeof(operand2),sizeof(operand1|operand2)); return 0; }
Ans:
0x100042 | 0x2 = 0x100042
8 4 8
The first row of output is the result of | operation.
0001 0000 0000 0000 0100 0010 | with
0000 0000 0000 0000 0000 0010 gives
0001 0000 0000 0000 0100 0010
Second row of output prints size of operand1, operand2, and operand1|operand2. operand1 is a long, operand2 is an int – result of | between a long and an int is a long. Hence we see sizeof long, int, and long printed in second row.
12. What is the result of following operations
1. 0x3B ^ 0xF0
0x3B | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 |
0xF0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
^ | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 1 |
Answer: 0xCB
2. 0xFF ^ 0x01
0xFF | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
0x01 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
^ | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
Answer: 0xFE
3. 0xFF ^ 0x00
0xFF | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
0x00 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
^ | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Answer: 0xFF
4. 0X87 ^ 0x78
0x87 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
0x78 | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
^ | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Answer: 0xFF
13. What is the result of following operations
1. ~0x3B
0x3B | 0 | 0 | 1 | 1 | 1 | 0 | 1 | 1 |
~ | 1 | 1 | 0 | 0 | 0 | 1 | 0 | 0 |
Answer: 0xC4
2. ~0xFF
0xFF | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
~ | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Answer: 0x00
3. ~0x00
0x00 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
~ | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Answer: 0xFF
4. ~0X87
0x87 | 1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
~ | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
Answer: 0x78
14. What will be the output of following program
#include <stdio.h> int main(int argc, char * argv[]) { unsigned char result = 0; unsigned char operand1 = 1; result=operand1<<3; printf("%x\n", result); return 0; }
Ans: 8
The value of the integer is set to 1, which is 0x1
0x1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
0x1 << 2 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
The program output will simply be “8”
15. What will be the result of following statements, assume signed char data type is used for storing all operands:
1. 0x4 << 1
0x4 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
<< 1 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
Answer: 0x8
2. 0x-1 << 1
-0x01 | X | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
<< 1 | X | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Answer: -0x02
3. 0xA << 1
0xA | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
<< 1 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
Answer: 0x14
16. What will be the result of following statements, assume unsigned char data type is used for storing all operands.
1. 0x4 >> 2
0x4 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
>> 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
Answer: 0x1
2. 0x1 >> 1
0x1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
>> 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Answer: 0x0
3. 0xA >> 1
0xA | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 |
>> 2 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 |
Answer: 0x5
17. Write a program to determine behaviour of right shift on negative numbers for your system. Such a program would start with a negative integer and observe the value after successive right shift operations.
Ans: Depending on your system, this program may run into an infinite loop but it would still help you understand inner representation and behavior of right shift. Refer to bit level details in the book and twos complement article for details on inner representation.
#include <stdio.h> int main (int argc, char * argv[]) { int num = -1; printf("%x\n", num); while(num) { num >>= 1; printf("%x\n", num); } return 0; }
18. Write a code snippet to clear out ip flag in the above example. Plug it into a program and validate your code.
Ans:
flags = flags & (~(0x01 << ip_flag));
19. Determine endianness of your system.
Ans: Simply run the endianess program in the book and observe results on your system.
20. Modify the above example for determining endianness by using value 0x12345678 instead of 0x1.
Ans:
#include <stdio.h> int main (int argc, char *argv[]) { int i = 0x12345678; char * ptr = &i; if (0x78 == *ptr) { printf("Little Endian\n"); } else { printf("Big Endian\n"); } }
21. Write a program to check if an integer is power of two.
#include <stdio.h> int main () { int num; // Prompt user to enter a number printf("Enter a number: "); scanf("%d", &num); // a number which is a power of two will // have ONLY one bit set in the integer // To find out using the bitwise operator // AND it with its n - 1 // a n-1 of a number which is a power // of two will have all the following // bits toggled. Like // 8 = 1000, 8-1 = 7 will be 0111 // 16 = 0001 0000, 15 will be 0000 1111 // & on n and n-1 for a number that is power of // two will result in 0. if ( (num != 0) && ((num & (num - 1)) == 0) ) { printf("The number %d is a power of two", num); } else { printf("The number %d is not a power of two", num); } return 0; }
22. Write a program that checks if an integer is negative by checking its MSB.
#include <stdio.h> int main (int argc, char *argv[]) { int num = 0; printf("Enter a number: "); scanf("%d", &num); if (num & (1<<(sizeof(int)*8-1))) { printf("Negative number\n"); } else { printf("Positive number\n"); } }
23. Write a program to count total number of set bits in an integer. A set bit has value 1.
#include <stdio.h> int main () { int i, count = 0; // Prompt user to enter a number printf("Enter a number: "); scanf("%d", &i); while (i) { if( (i & 1) == 1) // is the first bit set, then { count++; // increment count. } i = i >> 1; // Shift right, if no bits left i will be 0 } printf("Number of bits set are %d\n", count); return 0; }