C ++最大功率为2 <= n

时间:2013-11-26 03:21:14

标签: c++

如何计算2的最大功率&lt; =某个数字n?

现在我正在使用floor(log(n)/ log(2)+。05)但它似乎并不是所有n都可靠。有没有更清洁的东西/没有舍入错误的摆布?

4 个答案:

答案 0 :(得分:3)

我认为这个数字是无符号的。您可以使用二进制表示的知识。

该数字将是1在相同MSB位置并且全部为零的数字。

以下循环可以帮助您。

do {
    y = x;
    x = x&(x-1);
}while(x);
return y;

其中x是原始数字,y是结果。

下面给出了免费分支代码。

unsigned flp2(unsigned x) {
  x = x| (x>>1);
  x = x| (x>>2);
  x = x| (x>>4);
  x = x| (x>>8);
  x = x| (x>>16);
return x - (x>>1);
}

或(指望循环展开,所有现代编译器都可以这样做)

unsigned log2(unsigned x)
{
  for (int i = 0; i < std::numeric_limits<unsigned>::digits; i*=2)
     x |= (x>>i);
  return x - (x>>1);
}

来源:Hacker's Delight。

答案 1 :(得分:2)

我不完全确定你所针对的是哪种整体类型,所以在要求全部覆盖它们的要求下......

#include <iostream>
#include <cmath>

template<typename T>
typename std::enable_if<std::is_integral<T>::value,T>::type fn(T N)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    return T(1) << static_cast<T>(std::floor(std::log2(N)));
}

int main()
{
    std::cout << fn(4095) << std::endl;
    std::cout << fn(4096) << std::endl;
    std::cout << fn(4097) << std::endl;
    std::cout << fn(281474976710655) << std::endl;
    std::cout << fn(281474976710656) << std::endl;
    std::cout << fn(281474976710657) << std::endl;
    return 0;
}

<强>输出

typename std::enable_if<std::is_integral<T>::value, T>::type fn(T) [T = int]
2048
typename std::enable_if<std::is_integral<T>::value, T>::type fn(T) [T = int]
4096
typename std::enable_if<std::is_integral<T>::value, T>::type fn(T) [T = int]
4096
typename std::enable_if<std::is_integral<T>::value, T>::type fn(T) [T = long]
140737488355328
typename std::enable_if<std::is_integral<T>::value, T>::type fn(T) [T = long]
281474976710656
typename std::enable_if<std::is_integral<T>::value, T>::type fn(T) [T = long]
281474976710656

答案 2 :(得分:1)

在二进制中(假设您有一个整数类型),2的最大幂是最高位

有几种方法可以有效地计算

最有效的是使用内置函数,该内置函数使用可在一个周期内执行的机器代码

效率最低的是循环删除最低位

如果您不能使用内置插件,我喜欢这个:

unsigned int v;  // 32-bit value to find the log2 of 
const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
const unsigned int S[] = {1, 2, 4, 8, 16};
int i;

register unsigned int r = 0; // result of log2(v) will go here
for (i = 4; i >= 0; i--) // unroll for speed...
{
  if (v & b[i])
  {
    v >>= S[i];
    r |= S[i];
  } 
}

你可以在http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup

找到更多这样的内容

答案 3 :(得分:0)

此测试适用于32位有符号整数,其中 最佳 被分配给候选值2的最接近幂 x 在4到20亿的范围内:

for (int x = 4; x < (1<<31)-1; x++)
{
    int best = (int)(log((double)x)/log(2.0));

    int test = (int)pow((double)2, best);

    if (test > x || (test*2 <= x && test*2 > 0)) // test*2 < 0 when very large
        break; // fail
}