I am working on a function that takes a 64bits integer as parameter and returns a 64bits integer with all set bits at the end.
01011001 -> 00001111 // examples
00010100 -> 00000011
I first thought about the following algorithm:
nb_ones = countSetBit(x)
int64 res = 1
for i from 1 to nb_ones+1:
res |= (1 << i)
Here countSetBit
is the one defined here
Is there something more straightforward ? I am working in C++
countSetBit is probably something that's optimized for your platform already.
To set a given number of ones at the end, just go to the next power of two and subtract one.
nb_ones = countSetBit(x)
int64 res = nb_ones == 64 ? -1 : ((1 << nb_ones) - 1);
Edit: Nice non-branching solution from MSalters' comment:
int64_t res = ((1^(nb_ones>>6))<<nb_ones)-1;
(the 6th bit in nb_ones is one if-and-only-if nb_ones==64)
The background for the undefined behavior for << 64 is probably that the corresponding native operation might only use the bits of the argument needed for the maximum reasonable shift value, and handling this on the C++ side would add overhead.
You can avoid the loop:
const auto nb_ones = countSetBit(x)
if (nb_ones == 64) {
return -1; // 0xFFFFFFFFFFFFFFFF;
} else {
return (1u << nb_ones) - 1;
}
Counting all bits is a bit overkill as most CPU's have an efficient test against zero.
So, what we do is use that as the exit condition:
output = 0;
while (input != 0) {
if (input & 1) output = (output<<1)+1;
input >>= 1;
}
The loop shifts the input to the right, adding one extra bit to output
whenever a bit is shifted out of input
. Clearly this adds as many bits to output
as there are in input
(possibly 0, possibly 64). But the bits in output
are contiguous as output
is only shifted when a bit is added.
If your CPU has a bitcount operation, that's going to be faster of course. And if you'd implement this in x86 or ARM assembly, you'd use the fact that input&1
is the same bit that is shifted out by >>=1
.
Since you have several efficient answers, when you actually asked for a straightforward one, have a slow-but-conceptually-very-simple answer for variety:
uint64_t num(uint64_t x)
{
// construct a base-2 string
auto s = std::bitset<64>(x).to_string();
// sort the 1s to the end
std::sort(begin(s), end(s));
// and convert it back to an integer
return std::bitset<64>(s).to_ulong();
}
I think you can do it with just a single loop:
std::uint64_t bits_to_end(std::uint64_t n)
{
std::uint64_t x = 0;
for(std::uint64_t bit = 0, pos = 0; bit < 64; ++bit)
if(n & (1ULL << bit))
x |= (1ULL << pos++);
return x;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.