Solutions: Lecture 3 In-Class Exercises¶
Instructor key for exercises.md. Keep separate from the student
handout.
Part A - Number systems¶
Exercise A1 - The 0 to 15 table¶
| Decimal | Binary (4 bits) | Hex |
|---|---|---|
| 0 | 0000 | 0 |
| 1 | 0001 | 1 |
| 2 | 0010 | 2 |
| 3 | 0011 | 3 |
| 4 | 0100 | 4 |
| 5 | 0101 | 5 |
| 6 | 0110 | 6 |
| 7 | 0111 | 7 |
| 8 | 1000 | 8 |
| 9 | 1001 | 9 |
| 10 | 1010 | A |
| 11 | 1011 | B |
| 12 | 1100 | C |
| 13 | 1101 | D |
| 14 | 1110 | E |
| 15 | 1111 | F |
Talking points: bit 0 toggles every row, bit 1 every 2 rows, bit 2 every 4, bit 3 every 8 - each bit turns over twice as slowly as the one to its right.
Exercise A2 - Bigger conversions¶
| Decimal | Binary (8 bits) | Hex |
|---|---|---|
| 42 | 0010 1010 | 0x2A |
| 255 | 1111 1111 | 0xFF |
| 128 | 1000 0000 | 0x80 |
| 200 | 1100 1000 | 0xC8 |
| 58 | 0011 1010 | 0x3A |
Check the nibble-to-hex mapping: 0010 1010 -> 2 A, 1100 1000 -> C 8. Each
group of 4 bits is read off the A1 table independently.
Exercise A3 - Binary addition¶
0010 1101 (45) + 0001 0011 (19) = 0100 0000 (64). Check: 45 + 19 = 64.0100 0000 (64) + 0100 0000 (64) = 1000 0000 (128). Check: 64 + 64 = 128.1111 1111 (255) + 0000 0001 (1). By hand this is1 0000 0000(256), but the result does not fit in 8 bits: the low 8 bits are0000 0000and the1is a carry out off the top. In a fixed-width unsigned byte this is overflow, and255 + 1wraps to0.
Part B - Bits in C¶
Exercise B1 - Print a number in decimal, hex, and binary¶
#include <stdio.h>
void print_binary(unsigned int v) {
for (int i = 31; i >= 0; i--) {
printf("%c", (v >> i) & 1 ? '1' : '0');
if (i % 8 == 0 && i != 0) {
printf(" "); /* space every 8 bits, for readability */
}
}
printf("\n");
}
int main(void) {
unsigned int v;
printf("Enter a number: ");
scanf("%u", &v);
printf("decimal: %u\n", v);
printf("hex: 0x%X\n", v);
printf("binary: ");
print_binary(v);
return 0;
}
(v >> i) & 1slides bitidown to position 0 and keeps only that bit.- Stretch (skip leading zeros): find the highest set bit first, then print from there down.
Exercise B2 - Set, clear, toggle, test¶
#include <stdio.h>
void print_binary(unsigned int v) { /* reused from B1 */
for (int i = 31; i >= 0; i--) {
printf("%c", (v >> i) & 1 ? '1' : '0');
}
printf("\n");
}
int is_set(unsigned int x, int n) {
return (x >> n) & 1;
}
int main(void) {
unsigned int flags = 0;
flags |= (1 << 1); /* set bit 1 */
flags |= (1 << 3); /* set bit 3 */
print_binary(flags); /* ...0000 1010 */
flags &= ~(1 << 1); /* clear bit 1 */
print_binary(flags); /* ...0000 1000 */
flags ^= (1 << 0); /* toggle bit 0 on */
print_binary(flags); /* ...0000 1001 */
flags ^= (1 << 0); /* toggle bit 0 off */
print_binary(flags); /* ...0000 1000 */
printf("bits set (0-7): ");
for (int n = 0; n <= 7; n++) {
if (is_set(flags, n)) {
printf("%d ", n);
}
}
printf("\n"); /* prints: 3 */
return 0;
}
Why each idiom works:
|= (1 << n)- OR with a1forces bitnon; OR with0leaves the others untouched.&= ~(1 << n)-~(1 << n)is all1s with a single0at positionn; AND with0forces that bit off, AND with1leaves the rest.^= (1 << n)- XOR with1flips, XOR with0leaves unchanged - so only bitnflips.(x >> n) & 1- move bitnto the bottom, mask off everything else.
Stretch¶
1. Population count (set bits)¶
int popcount(unsigned int v) {
int count = 0;
for (int i = 0; i < 32; i++) {
count += (v >> i) & 1;
}
return count;
}
2. XOR swap¶
It works because XOR is its own inverse: x ^ y ^ y == x. (Caveat worth saying out
loud: if a and b are the same variable, this zeroes it - so a temporary is
usually the clearer choice in real code.)
3. Pack and unpack an RGB color¶
unsigned int color = (r << 16) | (g << 8) | b;
unsigned int red = (color >> 16) & 0xFF;
unsigned int green = (color >> 8) & 0xFF;
unsigned int blue = color & 0xFF;
The & 0xFF keeps just the low 8 bits (one channel) after shifting it down. This
is exactly how colors are stored in image formats - the practical payoff from
Section 5 of the notes.