讨论了获得最高1 位的各种方法here,其中还提到了您描述的移位方法。来自那里的详细答案:
使用查找表查找整数的以 2 为底的对数
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];
}
查找表方法只需要大约 7 次操作即可找到 32 位值的日志。如果扩展到 64 位数量,大约需要 9 次操作。另一个操作可以通过使用四个表来修剪,每个表都包含可能的添加。使用 int 表格元素可能会更快,具体取决于您的架构。
上面的代码被调整为均匀分布的输出值。如果您的输入均匀分布在所有 32 位值中,请考虑使用以下内容:
if (tt = v >> 24)
{
r = 24 + LogTable256[tt];
}
else if (tt = v >> 16)
{
r = 16 + LogTable256[tt];
}
else if (tt = v >> 8)
{
r = 8 + LogTable256[tt];
}
else
{
r = LogTable256[v];
}
最初通过算法生成日志表:
LogTable256[0] = LogTable256[1] = 0;
for (int i = 2; i < 256; i++)
{
LogTable256[i] = 1 + LogTable256[i / 2];
}
LogTable256[0] = -1; // if you want log(0) to return -1
Behdad Esfahbod 和我在 2005 年 5 月 18 日(平均而言)削减了一部分手术。2006 年 11 月 14 日,Emanuel Hoogeveen 又取消了另一部分手术。 David A. Butterfield 在 2008 年 9 月 19 日提出了调整到均匀分布输入值的变化。Venkat Reddy 在 2009 年 1 月 5 日告诉我 log(0) 应该返回 -1 以指示错误,所以我更改了表中的第一个条目。