Say for example I have a uint8_t that can be of any value, and I only want to flip all the bits from the least significant bit up to the most significant last 1 bit value? How would I do that in the most efficient way?, Is there a solution where I can avoid using a loop?
here are some cases:
left side is the original bits - right side after the flips.
00011101->0000001000000000->0000000011111111->0000000011110111->0000100001000000->00111111
[EDIT]
The type could also be larger than uint8_t, It could be uint32_t, uint64_t and __uint128_t. I just use uint8_t because it's the easiest size to show in the example cases.
CodePudding user response:
In general I expect that most solutions will have roughly this form:
- Compute the mask of bits that need to flipped
- XOR by that mask
As mentioned in the comments, x64 is a target of interest, and on x64 you can do step 1 like this:
- Find the 1-based position
pof the most significant 1, by leading zeroes (_lzcnt_u64) and subtracting that from 64 (or 32 whichever is appropriate). - Create a mask with
pconsecutive set bits starting from the least significant bit, probably using_bzhi_u64.
There are some variations, such as using BitScanReverse to find the most significant 1 (but it has an ugly case for zero), or using a shift instead of bzhi (but it has an ugly case for 64). lzcnt and bzhi is a good combination with no ugly cases. bzhi requires BMI2 (Intel Haswell or newer, AMD Zen or newer).
Putting it together:
x ^ _bzhi_u64(~(uint64_t)0, 64 - _lzcnt_u64(x))
Step 1 could also be implemented in a generic way (no special operations) using a few shifts and bitwise ORs, like this:
m = x | (x >> 1);
m |= m >> 2;
m |= m >> 4;
m |= m >> 8;
m |= m >> 16;
m |= m >> 32; // last step should be removed if x is 32-bit
CodePudding user response:
Here’s a simple example for 32 bit ints that works with gcc and compatible compilers (clang et al):
uint32_t flip(uint32_t n)
{
if (n == 0) return 0;
uint32_t mask = (uint32_t)~0 >> __builtin_clz(n):
return n ^ mask;
}
CodePudding user response:
Would you please try:
typedef uint8_t type; // or whatever
type myflip(type x)
{
int y = x;
int mask;
for (mask = 1; y; y >>= 1, mask <<= 1);
return ~x & (mask - 1);
}
