2的最大功率的有效计算< X

时间:2013-04-14 16:58:31

标签: c math

我需要计算2的最大功率,即<整数值,x

目前我正在使用:

#define log2(x) log(x)/log(2)
#define round(x) (int)(x+0.5)

x = round(pow(2,(ceil(log2(n))-1)));

这是一个性能关键功能

是否有一种计算效率更高的计算方法?

6 个答案:

答案 0 :(得分:3)

您实际上是在寻找数字中最高的非零位。许多处理器都有内置的指令,而这些指令又由许多编译器公开。例如,在GCC中,我会查看__builtin_clz,其中

  

从最高有效位开始,返回x中前导0位的数量。

sizeof(int) * CHAR_BIT和移位一起,您可以使用它来计算相应的纯二次幂整数。还有一个长整数的版本。

(CPU指令可能被称为“CLZ”(计数前导零),以防您需要查看其他编译器。)

答案 1 :(得分:2)

基于Sean Eron Anderson的Bit Twiddling Hacks: Find the log base 2 of an N-bit integer in O(lg(N)) operations(由Eric Cole和Andrew Shapira提供的代码):

unsigned int highest_bit (uint32_t v) {
    unsigned int r = 0, s;
    s = (v > 0xFFFF) << 4; v >>= s; r |= s;
    s = (v > 0xFF  ) << 3; v >>= s; r |= s;
    s = (v > 0xF   ) << 2; v >>= s; r |= s;
    s = (v > 0x3   ) << 1; v >>= s; r |= s;
    return r | (v >> 1);
}

返回输入最高位的索引; 2的最大幂不大于输入1 << highest_bit(x),因此2的最大幂大于输入,因此只是1 << highest_bit(x-1)

对于64位输入,只需将输入类型更改为uint64_t,并在函数开头添加以下额外行,在变量声明之后:

    s = (v > 0xFFFFFFFF) << 8; v >>= s; r |= s;

答案 2 :(得分:2)

我的c-libutl库中有一个整数log2函数(如果有人有兴趣,可以在googlecode上托管)

/*
** Integer log base 2 of a 32 bits integer values.
**   llog2(0) == llog2(1) == 0
*/
unsigned short llog2(unsigned long x)
{
  long l = 0;

  x &= 0xFFFFFFFF /* just in case 'long' is more than 32bit */

  if (x==0) return 0;

  #ifndef UTL_NOASM
    #if defined(__POCC__) || defined(_MSC_VER) || defined (__WATCOMC__)
        /* Pelles C            MS Visual C++         OpenWatcom */
      __asm { mov eax, [x]
              bsr ecx, eax
              mov  l, ecx
      }
    #elif defined(__GNUC__)
      l = (unsigned short) ((sizeof(long)*8 -1) - __builtin_clzl(x));
    #else
      #define UTL_NOASM
    #endif  
  #endif

  #ifdef UTL_NOASM  /* Make a binary search.*/
    if (x & 0xFFFF0000) {l += 16; x >>= 16;} /* 11111111111111110000000000000000 */
    if (x & 0xFF00)     {l += 8;  x >>= 8 ;} /* 1111111100000000*/
    if (x & 0xF0)       {l += 4;  x >>= 4 ;} /* 11110000*/
    if (x & 0xC)        {l += 2;  x >>= 2 ;} /* 1100 */
    if (x & 2)          {l += 1;  }          /* 10 */
    return l;
  #endif

  return (unsigned short)l;
}

然后你可以简单地计算

 (1 << llog2(x))

计算小于x的2的最大幂。当心0!你应该单独处理它。

它使用汇编代码,但也可以通过定义UTL_NOASM符号强制为纯C代码。

该代码当时已经过测试,但很长一段时间我没有使用它,我不能说它是否在64位环境中运行。

答案 3 :(得分:0)

转移位置很可能会快得多。可能一些比特的二分法可以使它更快。很好的运动,以改善。

#include <stdio.h>

int closestPow2(int x)
{
        int     p;

        if (x <= 1) return 0; /* No such power exists */

        x--;   /* Account for exact powers of 2, then one power less must be returned */
        for (p = 0; x > 0; p++)
        {
                x >>= 1;
        }

        return 1<<(p-1);
}

int main(void)
{
        printf("%x\n", closestPow2(0x7FFFFFFF));
        return 0;
}

答案 4 :(得分:0)

左右移位操作符最佳

int MaxPowerOf2(int x)
{
   int out = 1;
   while(x > 1) { x>>1; out<<1;}
   return out;
}

答案 5 :(得分:0)

#include <math.h>  

double greatestPower( double x )  
{  
    return floor(log( x ) / log( 2 ));  
}

自单log单调递增函数以来就是如此。