我怎么能找到两个不是没有循环的数字的最大功率?

时间:2013-01-25 17:45:14

标签: c++ algorithm

如何在没有循环的情况下找到小于2的最大功率? 例子:

5 output = 4.
11 output = 8.
100 output = 64.

6 个答案:

答案 0 :(得分:10)

使用整数来进行一些有趣的方法是:

// given an int number (which would be the upper value of the range)
number |= number >> 1;
number |= number >> 2;
number |= number >> 4;
number |= number >> 8;
number |= number >> 16;
return (number >> 1) + 1;

想法是将01010转为01111,转一次得到00111然后加一来得到01000的结果。

要了解其工作原理,请考虑输入为0或非零。如果它为0,那么结果为0 + 1,因为所有的移位和oring只导致0(2增加到0次幂是1,最低功率2,输入0的答案)。

对于非零数字,位中的某个位置是该值的最重要的设置位。我们想要的答案是没有跟踪它的所有较小的重要位。所以专注于那一点,因为这是我们真正关心的。当我们以第一个右移1进行按位或运算时,我们确保仍然设置最高有效设置位,并且设置比它小一个的位,因为0100 | 0010 = 0110.接下来我们或者说它本身,但这次换了两次。这确保了我们有MSB加3个尾随位。我们一直这样做,直到达到int中的位数限制。以下是一个完整的32位值示例的逐步步骤:

01000000110100111000000011010011

01000000000100000000000010000010 |
00100000000010000000000001000001 = 01100000000110000000000011000011 (num |= num >> 1)

01100000000110000000000011000011 |
00011000000001100000000000110000 = 01111000000111100000000011110011 (num |= num >> 2)

01111000000111100000000011110011 |
00000111100000011110000000001111 = 01111111100111111110000011111111 (num |= num >> 4)

01111111100111111110000011111111 |
00000000011111111001111111100000 = 01111111111111111111111111111111 (num |= num >> 8)

01111111111111111111111111111111 |
00000000000000000111111111111111 = 01111111111111111111111111111111 (num |= num >> 16)

现在剩下要做的就是将最终值右移一位,然后加一,将所有那些1变为0,除了最重要的进位,将我们想要的答案的位设置为1。

答案 1 :(得分:9)

假设您想要的最大功率小于x,则可以从

获得
Ans=pow(2,floor(log(x)/log(2)));

答案 2 :(得分:1)

如果n是范围的最大数

return int(math.log(n, 2));

答案 3 :(得分:0)

您可以使用数字的基于日志的2,它将为您提供功率,或者,如果它是一个整数,则获取最高位集的位置(但这可能需要循环)。

我暂时没有完成C ++,但在C#中它将是:

        double val = 129;
        int power = (int)(Math.Log10(val) / Math.Log10(2));

使用log n的规则(X)= log y (X)/ log y (n)

答案 4 :(得分:0)

// This only works if i >= 0, and it may overestimate by one power of 2
// if i is slightly less than a large power of 2. Fixing these issues is
// not difficult, so it's left as an exercise.
long largest_power_of_two(long i) {
  int exp;
  frexp(double(i), &exp);
  return long(ldexp(0.5, exp));
}

frexpldexp只是乱七八糟,因此在那里甚至没有隐藏的循环(除了微架构层之外)。

答案 5 :(得分:0)

您可以使用特殊的CPU指令(如果可用),例如x86 BSR

如果你可以在没有循环的情况下对位数进行位恢复(可能使用查找表或其他特殊的CPU指令),那么你可以恢复数字,找到最低有效位设置为1,重置其他位置并恢复回来了。

unsigned IsolateLeastSignificantOne(unsigned n)
{
  return n & -n;
}

n = BitRevert(IsolateLeastSignificantOne(BitRevert(n)));

有关比特技巧和其他有用的内容,请参阅this document