Exercise 2.6 - Setting bits at a position n¶
Question¶
Write a function setbits(x,p,n,y) that returns x with the n bits that begin at position p set to the rightmost n bits of y, leaving the other bits unchanged.
/**
*
* Exercise 2.6 - Write a function setbits(x,p,n,y) that returns x with the
* n bits that begin at position p set to the rightmost n bits of y,leaving
* the other bits unchanged.
**/
#include <stdio.h>
unsigned setbits(unsigned x, int p, int n, unsigned y);
int main(void) { printf("%u", setbits((unsigned)12, 3, 2, (unsigned)57)); }
unsigned setbits(unsigned x, int p, int n, unsigned y) {
return (x & ~(~(~0 << n) << (p + 1 - n))) |
(y & (~(~0 << n)) << (p + 1 - n));
}
Explanation¶
The important piece of the program is this:
(x & ~(~(~0 << n) << (p+1-n))) | ( y & (~(~0<<n) << (p+1-n)));
Let’s look at some inner terms. The expression ~(~0<<n) will thus always yield right most n bits set to 1. And (p+1-n) will give a integer value for the n digits at position p we want. We do p+1 because our position is 0 indexed while count of digits n is 1 indexed. For e.g. in a number 1111 1111, the 4 digits starting the position 3 is 1111
Let’s refactor the program to understandable portions.
RIGHT_MOST_N_1S = ~(~0 << n) GET_N_DIGITS = (p + 1 -n)
The above expression becomes:
(x & ~(RIGHT_MOST_N_1S << GET_N_DIGITS)) | (( y & RIGHT_MOST_N_1S) << GET_N_DIGITS);
For a moment, let’s take the word that left shifting operation will give us expected bits. For e.g: 0000 1111 << 4 will give us 1111 0000
Reducing it further, it becomes:
(x & ~(Expected bits marked as 1) | ((Right most bits in y) << GET_N_DIGITS);
(x & (Expected bits marked as 0) | (Expected bits marked as 1 in y and rest as 0);
So in x we switch off the expected bits by and ing it to 0. And and in y, we just get expected bits we want by and ing it to 1 and we OR the two expressions and thus get the result.
Why left shift?
We left shift because we want it from a position p.
Suppose we want two bits from position 4, we we need to our bit patterns to be like this:
0001 1000
7654 3210
In the above, from position 4, we have 2 bits set 1 and rest 0.
In order to do this, we get two bits at the right most position:
~(~0 << n)
0000 0011
And then we shift it by position 4 using the expression p+1-n:
~(~0 << n) << (4+1-n)
0000 0011 << (5-2)
0000 0011 << 3
0 0011 000
0001 1000
So we determined our expected bits and we can follow the rest for the program.
Let’s get concrete and work out the program using the values:
x = 1111 1111 (= 255 )
p = 3
y = 0000 0000 (= 0)
n = 4
setbits(unsigned x,int p,int n,unsigned y);
Right most 4 bits of y = 0000 So, we our return value should be:
= 1111 0000
= 240
Let’s follow how the program determines it. We take the LHS of |
(x & ~(~(~0 << n) << (p+1-n)))
p+1-n = 3 + 1 - 4
= 0
(~0 << n)
= (~ 0000 0000 << 4)
= (1111 1111 << 4)
= (1111 0000)
~(~0 << n)
= ~(1111 0000)
= 0000 1111
(~(~0 << n) << (p+1-n))
= 0000 1111 << 0
= 0000 1111
~(~(~0 << n) << (p+1-n))
= ~ (0000 1111)
= 1111 0000
(x & ~(~(~0 << n) << (p+1-n)))
= 1111 1111 & 1111 0000
= 1111 0000
Now we take the RHS of |
(( y & ~(~0<<n)) << (p+1-n))
(p + 1 - n) = 0
~(~0 << n) = 0000 1111
( y & ~(~0<<n))
= 0000 0000 & 0000 1111
= 0000 0000
(( y & ~(~0<<n)) << (p+1-n))
= 0000 0000 << 4
= 0000 0000
We write the entire expression:
(x & ~(~(~0 << n) << (p+1-n))) | (( y & ~(~0<<n)) << (p+1-n));
= 1111 0000 | 0000 0000
= 1111 0000
Converting 1111 0000 to decimal gives us 240 and that is answer.