与2 ^ n相反

时间:2010-10-11 13:16:47

标签: algorithm math bitwise-operators

通过执行a = 1 << b,可以快速计算任何b的函数a = 2 ^ b。 那么反过来说,为任何给定的a获得b的值?它应该相对较快,因此日志是不可能的。任何不是O(1)的东西也都不好。

我很高兴无法完成如果没有日志或搜索类型就无法做到。

7 个答案:

答案 0 :(得分:13)

建立一个查找表。对于32位整数,只有32个条目,因此它是O(1)。

大多数架构还有一条指令,用于查找数字 a 中最重要位的位置,即值 b 。 (gcc为此提供了__builtin_clz function。)

对于BigInt,可以通过重复除以2来计算O(log a)。

int b = -1;
while (a != 0) {
  a >>= 1;
  ++ b;
}

答案 1 :(得分:7)

对于这种事情,我通常会在这个页面上引用一些黑客攻击:

例如:

Find the log base 2 of an integer with a lookup table

static const char LogTable256[256] = 
{
#define LT(n) n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n
    -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
    LT(4), LT(5), LT(5), LT(6), LT(6), LT(6), LT(6),
    LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7), LT(7)
};

unsigned int v; // 32-bit word to find the log of
unsigned r;     // r will be lg(v)
register unsigned int t, tt; // temporaries

if (tt = v >> 16)
{
  r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt];
}
else 
{
  r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v];
}

该页面上还有一些O(log(n))算法。

答案 2 :(得分:2)

某些架构具有“计数前导零”指令。例如,在ARM上:

MOV R0,#0x80      @ load R0 with (binary) 10000000
CLZ R1,R0         @ R1 = number of leading zeros in R0, i.e. 7

这是O(1)。

答案 3 :(得分:2)

或者你可以写:

while ((a >>= 1) > 0) b++;

这是O(1)。可以想象这将扩展到:

b = (((a >> 1) > 0) ? 1 : 0) + (((a >> 2) > 0) ? 1 : 0) + ... + (((a >> 31) > 0) ? 1 : 0);

使用编译器优化,一旦(a >> x) > 0)返回false,就不会计算休息。与0比较也比任何其他比较更快。也: alt text,其中k最大为32,g为1。

参考:Big O notation

但是如果您使用BigInteger,那么我的代码示例将如下所示:

    int b = 0;
    String numberS = "306180206916083902309240650087602475282639486413"
            + "866622577088471913520022894784390350900738050555138105"
            + "234536857820245071373614031482942161565170086143298589"
            + "738273508330367307539078392896587187265470464";
    BigInteger a = new BigInteger(numberS);

    while ((a = a.shiftRight(1)).compareTo(BigInteger.ZERO) > 0) b++;

    System.out.println("b is: " + b);

答案 4 :(得分:1)

如果a是double而不是int,那么它将表示为尾数和指数。指数是您要查找的部分,因为这是数字的对数。

如果您可以破解二进制表示,那么您可以获得指数。查找IEEE标准以查看指数的存储位置和方式。

对于整数值,如果某个获取最高位位置的方法不可用,那么您可以二进制搜索最高1的位,因此为O(log numbits)。这样做实际上可能比先转换为双倍更快。

答案 5 :(得分:1)

在Java中,您可以使用Integer.numberOfLeadingZeros来计算二进制对数。它返回二进制表示中前导零的数量,所以

  • floor(log2(x))= 31 - numberOfLeadingZeros(x)
  • ceil(log2(x))= 32 - numberOfLeadingZeros(x - 1)

答案 6 :(得分:0)

如果不测试高位,就无法完成,但大多数现代FPU都支持log2,所以不会丢失所有内容。