Here we discuss how to insert a number m
into a number n
between positions i
and j
.
Let us see an example to better visualize what this means. Suppose we have the number n = 1040
and that we want to insert the number m = 19
into it, between positions i = 2
and j = 6
. As shown below, by doing so we obtain the number 1100:
We could go about this in a number of different ways. We’ll just do lazy here , meaning we make two very generous assumptions:
- The number of bits between
i
andj
is indeed the actual number of bits in numberm
. - There are enough bits in
n
for insertingm
into it.
With that out of the way, we can now focus on the task at hand. The tricky part is to zero-out the bits in number n
between positions i
and j
(in yellow in the figure above). To do this, we must create a bit mask that goes from 0
through j
and that has two parts:
- The “left”-most part (between positions
i
andj
) is all zeros (we want to zero-out this part ofn
). We can obtain it by left-shifting1
byj + 1
bits, subtracting1
, and finally inverting (logicalNOT
) the mask. - The “right”-most part (between positions
0
andi - 1
) is all ones (we want to keep this part ofn
). We can obtain it by left-shifting1
byi
bits, then subtracting1
.
Once that’s done, we must bring together the two parts of the mask using the logical OR
operator.
Next, we apply the mask to the number n
, thus clearing its bits at positions i
through j
. Now the only thing that’s left is to “insert” m
into n
between these indexes, which we can do by left-shifting m
by i
bits, followed by applying the logical OR
operator.
Here is how this algorithm can be implemented in C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Insert number `m` into number `n` between positions `j` through `i`.
// Assumption 1: the number of bits between `j` and `i` is the number of bits of `m`.
// Assumption 2: there are enough bits in `n` for inserting `m`.
int insert_number_inside_another(int n, int m, int i, int j)
{
/*
Create a mask that zeroes out bits from positions j through i (inclusive)
in n when using the AND operator between n and the mask.
The mask has the following form:
Mask: 1 ... 1 0 ... 0 1 ... 1
Positions: |n|-1 j+1 j i i-1 0
*/
int mask = ~((1 << (j + 1)) - 1) | ((1 << i) - 1);
// Apply the mask to turn off bits betwene j and i, then insert m.
return (n & mask) | (m << i);
}
Whew, that long explanation for only 2 lines of actual code, who would have thought?
Want to see more bitwise logic? There’s a whole repository on my GitHub on bit fiddling.
Comments powered by Disqus.