Is there an elegant way of moving a bit within a byte (or word/long). For simplicity, lets use a simple 8-bit byte and just one bit to move within the byte.
Given a bit number, based on 0-7 Least-sig-bit to most-sig-bit, (or bits 1-8 if you’d rather), I would like to move a bit from one position to another:
7654 3210 <bit position
0101 1010 <some binary value
--x- --y- <move bit from x to y
0111 0100 <new value with x moved to y and intervening bits shifted left
So, x at bit position 5 moves to y at bit position 1, bits 0,6,7 stay unchanged. Bits 2,3,4 are shifted left to ‘make room’ for the bit moved from 5 to 2. This is just an example.
It is important that the bit moves, not swapped with its target. There are numerous exampls of bits that swap, but that is quite trivial.
The solution ideally would use simple bit-twiddling and bitwise operators. Assume language agnostic, bit simple AND/OR/XOR, NOT, SHIFT Left/Right / ROTATE or similar instructions would be fine in any combination, plus any other basic arithmetic operator, eg: mod, addition/subtraction etc. Even working psuedo-code would be ok. Alternatively, a bit array or bitfield type structure would probably be straightforward.
In addition to the actual bit move, I would like to find a way to :
- Move any bit up or down.
- Specify the bit number source/destination in any convenient format: eg: 6>2
implies shift down, 3>7 shift up or start-bit +/- offset: 6-4 or 3+4, or bit weighted: bit 6=64 to bit 3=8. - Possibly extendable from byte to unsigned int, long, etc.
- (Ideally, be extendable
to more than one bit at a time, probably adjacent bits if easier)
Performance is not a major issue, but something elegant is likley to be plenty fast enough.
My own niaive approach would be to identify the source and target bit positions, decide if shift up or down, take a shifted copy, mask off the static bits and find the source bit, merge the static and shifted bits and somehow set/clear the target bit. However, while the theory seems good, an elegant implementation is beyond me.
I realise that a precompiled lookup table could be built for a byte, but if this is to be extended to integers/longs, this would be impractical for me.
Any help appreciated. Thanks in advance.
First, an observation about the original problem, and the subsequent extensions that you mention:
The “moving a bit” operation that you describe is really a rotation of a contiguous range of bits. In your example, you are rotating bits 1-5 inclusive, by one bit to the left:
If you consider a more general form of this operation to be “rotate a range of bits left by some amount” with three parameters:
then it becomes a single basic primitive which can perform all of the things you want to do:
So now, all that’s needed is to construct this primitive…
To start with, we’re almost certainly going to need a bit mask for the bits we care about.
We can form a mask for bits 0 – n by shifting a 1 by n + 1 bits to the left, then subtracting 1. e.g. a mask for bits 0-5 would be (in binary):
…which can be formed by taking a 1:
…shifting 5+1 = 6 bits to the left:
…and subtracting 1 to give:
In C, this would be
(1 << (bit + 1)) - 1. But there is a subtlety here, for C at least (and I apologise for the digression when you’ve tagged this as language-agnostic, but this is important, and there are probably similar issues in other languages too): a shift by the width of your type (or more) leads to undefined behaviour. So if we were trying to construct a mask for bits 0-7 for an 8-bit type, the calculation would be(1 << 8) - 1, which would be undefined. (It might work on some systems and some compilers, but wouldn’t be portable.) There are also undefined behaviour issues with signed types in the case where you would end up shifting into the sign bit.Fortunately, in C, we can avoid these problems by using an
unsignedtype, and writing the expression as(1 << bit) + (1 << bit) - 1. Arithmetic with unsigned n-bit values is defined by the standard to be reduced modulo 2n, and all of the individual operations are well-defined, so we’re guaranteed to get the right answer.(End of digression.)
OK, so now we have a mask for bits 0 – msb. We want to make a mask for bits lsb – msb, which we can do by subtracting the mask for bits 0 – (lsb-1), which is
(1 << lsb) - 1. e.g.So the final expression for the mask is:
The bits to be rotated can be selected by a bitwise AND with the mask:
…and the bits that will be left untouched can be selected by a AND with the inverted mask:
The rotation itself can be performed easily in two parts: first, we can obtain the leftmost bits of the rotated portion by simply rotating
to_rotateleft and discarding any bits that fall outside the mask:To get the rightmost bits, rotate
to_rotateright by (n – shift) bits, where n is the number of bits we’re rotating (this n can be calculated asmsb + 1 - lsb):The final result can be obtained by combining all the bits from
untouched,left, andright:Your original example would work like this (
msbis 5,lsbis 1, andshiftis 1):Here’s a different example with a 16-bit input value,
msb= 15,lsb= 4, andshift= 4 (which rotates the top 3 hex digits of a 4-digit hex value):