문제

Is there any way other than log_2(x) for determining which power an integer is ? Knowing of course that it is a power of two, (binary base 0001, 0010, 0100, 1000, etc...).
Mostly I don't want it to convert to a floating point number and I don't want it to simple use an array search.

도움이 되었습니까?

해결책

What you want to do is count the trailing zeroes of a number, although counting the leading zeroes and subtracting from 32 or 64 can work just as well when the number is a power of two. Bit Twiddling Hacks provides many ways to do this.

Count the consecutive zero bits (trailing) on the right linearly

unsigned int v;  // input to count trailing zero bits
int c;  // output: c will count v's trailing zero bits,
        // so if v is 1101000 (base 2), then c will be 3
if (v)
{
  v = (v ^ (v - 1)) >> 1;  // Set v's trailing 0s to 1s and zero rest
  for (c = 0; v; c++)
  {
    v >>= 1;
  }
}
else
{
  c = CHAR_BIT * sizeof(v);
}

Count the consecutive zero bits (trailing) on the right in parallel

unsigned int v;      // 32-bit word input to count zero bits on right
unsigned int c = 32; // c will be the number of zero bits on the right
v &= -signed(v);
if (v) c--;
if (v & 0x0000FFFF) c -= 16;
if (v & 0x00FF00FF) c -= 8;
if (v & 0x0F0F0F0F) c -= 4;
if (v & 0x33333333) c -= 2;
if (v & 0x55555555) c -= 1;

Count the consecutive zero bits (trailing) on the right by binary search

unsigned int v;     // 32-bit word input to count zero bits on right
unsigned int c;     // c will be the number of zero bits on the right,
                    // so if v is 1101000 (base 2), then c will be 3
// NOTE: if 0 == v, then c = 31.
if (v & 0x1) 
{
  // special case for odd v (assumed to happen half of the time)
  c = 0;
}
else
{
  c = 1;
  if ((v & 0xffff) == 0) 
  {  
    v >>= 16;  
    c += 16;
  }
  if ((v & 0xff) == 0) 
  {  
    v >>= 8;  
    c += 8;
  }
  if ((v & 0xf) == 0) 
  {  
    v >>= 4;
    c += 4;
  }
  if ((v & 0x3) == 0) 
  {  
    v >>= 2;
    c += 2;
  }
  c -= v & 0x1;
}

And three more examples which use floats and array lookups, which you've specified you do not want to use.

다른 팁

Several ways to do it. One on top of my head, you can divide it by 2, until it is 1:

int logbase2( unsigned int n ) {
    int exp = 0;
    if ( n == 0 )
        return -1;
    while ( n != 1 ) {
        n /= 2;
        exp++;
    }
    return exp;
}

And logbase2( yournumber ); shall yield the result you want. More generally, it shall yield the integer part of the actual logarithm on base 2 of the number yournumber.

You can use a bit comparison test based on iterating with a bit shift operation:

unsigned int power_of_2(unsigned int x) {
    // Note that *8 hardcoded isn't ideal here. There's a constant available that
    // specifies the 'byte' size (bitwise) for the actual architecture. 
    // But this is really depending on your C or C++ compiler.
    for(size_t p2 = 0; p2 < sizeof(x)*8; ++p2) { 
        if(x & (1 << p2)) {
            return p2;
        }
    }
    return 0;
}

The following calls give you the output shown below:

int main() {
    std::cout << power_of_2(0x0080) << " "
              << power_of_2(0x0040) << " "
              << power_of_2(0x0020) << " "
              << power_of_2(0x0010) << " "
              << std::endl;
    return 0;
}

Output:

7 6 5 4 

Check a live sample here please.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top