问题
I am currently trying to write an algorithm that determines how many bits are necessary to represent a number x. My implementation will be in c. There are a few catches though, I am restricted to pretty much just the bitwise operators {~, &, ^, |, +, <<, >>}. Also, I cannot use any type of control flow (if, while, for). My original approach was to examine the number in binary from left to right, and look for where there is an occurrence of the first '1'. I am not sure how to approach this given the restrictions I have. The number I am working with can be considered an unsigned integer. So 00110 would require only 3 bits.
I am wondering if there is a much easier/cleaner way to do this and I am missing it? Or if someone can give a few hints?
Basically, I was trying to implement this without the while loop:
int result = 0;
while (x >>= 1) {
result += 1;
}
return result;
回答1:
http://www-graphics.stanford.edu/~seander/bithacks.html#IntegerLog
Shows how to do it without control flow.
unsigned int v; // 32-bit value to find the log2 of
register unsigned int r; // result of log2(v) will go here
register unsigned int shift;
r = (v > 0xFFFF) << 4; v >>= r;
shift = (v > 0xFF ) << 3; v >>= shift; r |= shift;
shift = (v > 0xF ) << 2; v >>= shift; r |= shift;
shift = (v > 0x3 ) << 1; v >>= shift; r |= shift;
r |= (v >> 1);
r++;
回答2:
Accepted answer is actually wrong: e.g. it outputs 5 for 32..63 (instead of 6), 4 for 16..31 (instead of 5). It's like taking the base 2 logarithm and rounding down.
The correct solution is as follows:
unsigned int v; // 32-bit value to find the log2 of
register unsigned int r; // result of log2(v) will go here
register unsigned int shift;
r = (v > 0xFFFF) << 4; v >>= r;
shift = (v > 0xFF ) << 3; v >>= shift; r |= shift;
shift = (v > 0xF ) << 2; v >>= shift; r |= shift;
shift = (v > 0x3 ) << 1; v >>= shift; r |= shift;
r |= (v >> 1);
r++;
Note the r++.
回答3:
Please try:
// http://www.cs.northwestern.edu/~wms128/bits.c
int check_bits_fit_in_2s_complement(signed int x, unsigned int n) {
int mask = x >> 31;
return !(((~x & mask) + (x & ~mask))>> (n + ~0));
}
回答4:
I have a solution. It is not fast. It calculates the number of bits needed, i.e. 32 for 0xFFFFFFFF and 0 for 0x00000000. Note that your C code really calculates the most significant bit or zero.
Here it is:
#define ISSET(x,i) (((x) >> (i)) & 1)
#define FILL(x) (-(x))
#define IF(x,y,z) ((FILL(x) & y) | (~FILL(x) & z))
#define R(x,i,y,z) (IF(ISSET(x,i),y,z))
int log2 (uint32_t x)
{
return R(x,31,32,
R(x,30,31,
R(x,29,30,
R(x,28,29,
R(x,27,28,
R(x,26,27,
R(x,25,26,
R(x,24,25,
R(x,23,24,
R(x,22,23,
R(x,21,22,
R(x,20,21,
R(x,19,20,
R(x,18,19,
R(x,17,18,
R(x,16,17,
R(x,15,16,
R(x,14,15,
R(x,13,14,
R(x,12,13,
R(x,11,12,
R(x,10,11,
R(x, 9,10,
R(x, 8, 9,
R(x, 7, 8,
R(x, 6, 7,
R(x, 5, 6,
R(x, 4, 5,
R(x, 3, 4,
R(x, 2, 3,
R(x, 1, 2,
R(x, 0, 1, 0))))))))))))))))))))))))))))))));
}
Note: The general principle can be used for other functions.
回答5:
Well, I think he needs a first-bit-counter rather than last-bit-counter. Since this algorithm imply 32bit integer, there's fixing needed by the result.
unsigned int v; // 32-bit value to find the log2 of
register unsigned int r; // result of log2(v) will go here
register unsigned int shift;
r = (v > 0xFFFF) << 4; v >>= r;
shift = (v > 0xFF ) << 3; v >>= shift; r |= shift;
shift = (v > 0xF ) << 2; v >>= shift; r |= shift;
shift = (v > 0x3 ) << 1; v >>= shift; r |= shift;
r |= (v >> 1);
return 32-r;
来源:https://stackoverflow.com/questions/9105713/of-bits-needed-to-represent-a-number-x