[SOLVED] Preserving sign during a masking operation

Issue

I have a 16 bit word (short). I would like to take the lower 13 bits and save them in a new short while preserving the sign (i.e if bit 12 is a 1, then I want bits 13-15 in the new word to also be 1, but if bit 12 is a 0, then I want bits 13-15 in the new word to be 0).

For example, if I have

short a = 0xDADD // 0b1101101011011101
short b = 0xFADD // 0b1111101011001110

or

short a = 0xABCD // 0b1010101111001101
short b = 0x0BCD // 0b0000101111001101

I can do it with conditionals, but I’d like to try and avoid that if I can and stick to as few bitwise operations as possible. Another option would be to do a 3-bit shift to the left followed by a 3-bit arithmetic right shift, but it’s my understanding that most C compilers interpret the >> operator as a logical shift. Is there a way to force an arithmetic shift?

Thanks in advance

Solution

You can do this with (x & 0x1fff ^ 0x1000) - 0x1000. After masking the low 13 bits, this flips bit 12 and subtracts 4096 (212).

To see this works, consider value b (0 or 1) for bit 12 and value c (0 to 4095) for bits 11 to 0. In a 13-bit two’s complement representation, bit 12 represents −4096, so the represented value is −4096•b + c. Instead, in our wider integer type, we have 4096•b + c. Flipping b gives 4096•(1-b) + c, and then subtracting 4096 gives 4096•(−b) + c = −4096•b + c, which is the desired result.

Answered By – Eric Postpischil

Answer Checked By – Robin (BugsFixing Admin)

Leave a Reply

Your email address will not be published.