Sign Extension and Masking in an 8-Bit Motor Command
A robotics club uses one 8-bit byte per motor command. Bits 7-4 hold motor ID (0-15); bits 3-0 hold a signed 4-bit two's complement speed in the range -8 to 7. A student writes packed = (motorId << 4) | speed; and decodes with motorId = packed >> 4; and speed = packed & 0x0F;. Tests with motor 9 and speed 3 work. Tests with motor 9 and speed -3 arrive as motor 15 with speed 13. A test with speed -8 also misbehaves. The student thinks the problem is the motor, but the same motor works at positive speeds. The club needs a corrected encode/decode pair and a test plan before the next competition.
1. Explain why speed -3 corrupts both the motor ID and the decoded speed. Use the 4-bit two's complement representation in your answer.
Read the worked answer
In 4-bit two's complement, -3 is 1101. But in a 32-bit int, -3 is 111...11101, so (motorId << 4) | speed ORs all those high 1 bits into the packed value. For motor 9, 9 << 4 is 0x90; OR with -3 makes the whole value negative and destroys the motor ID. Decoding with packed >> 4 then gives a negative or all-ones motor ID, and packed & 0x0F gives 1101 = 13, not -3. The fix has two parts: mask the speed to four bits before packing, (motorId << 4) | (speed & 0x0F), and sign-extend after decoding: int s = packed & 0x0F; if (s >= 8) s -= 16;. Also validate motorId 0-15 and speed -8 to 7 before packing; 8 is not a valid 4-bit signed speed even though it fits in four bits.
2. Give corrected code and at least five test cases with expected packed byte and decoded values, including -8, -1, 0, 7, and an invalid speed such as 8.
Read the worked answer
Corrected encode: int packed = ((motorId & 0x0F) << 4) | (speed & 0x0F);. Decode: int motor = (packed >> 4) & 0x0F; int s = packed & 0x0F; if (s >= 8) s -= 16;. Test cases for motor 9: speed -8 gives low nibble 8, packed 0x98 (152), decoded -8; speed -3 gives 0x9D (157), decoded -3; speed -1 gives 0x9F (159), decoded -1; speed 0 gives 0x90 (144), decoded 0; speed 7 gives 0x97 (151), decoded 7; speed 8 should be rejected before packing, because masking would make it 8 and decode as -8. Also test motor 0 and motor 15 to check the high nibble, and round-trip every valid pair. The key reasoning is that the packed byte is just a container; signedness is restored only by the decode step.