通过执行a = 1 << b
,可以快速计算任何b的函数a = 2 ^ b。
那么反过来说,为任何给定的a获得b的值?它应该相对较快,因此日志是不可能的。任何不是O(1)的东西也都不好。
我很高兴无法完成如果没有日志或搜索类型就无法做到。
答案 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比较也比任何其他比较更快。也:
,其中k最大为32,g为1。
但是如果您使用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来计算二进制对数。它返回二进制表示中前导零的数量,所以
答案 6 :(得分:0)
如果不测试高位,就无法完成,但大多数现代FPU都支持log2,所以不会丢失所有内容。