特殊情况下的快速整数对数

时间:2010-12-11 04:40:36

标签: c optimization integer bit-manipulation logarithm

我有32-8191的整数值,我想要映射到一个大致对数的比例。如果我使用base 2,我可以计算前导零位并将它们映射到8个插槽,但这也是过程粗糙的;我需要32个插槽(更多会更好,但我需要它们映射到32位值中的位),这对于对数大约为1.18-1.20。任何人都有一些技巧来计算这个值,或者是一个合理的近似值,非常快?

我的直觉是用条件将范围分解为2或3个子范围,并为每个使用一个小的查找表,但我想知道是否有一些技巧我可以用count-leading-zeros然后改进结果,特别是因为结果不一定是精确的,而只是大致对数。

3 个答案:

答案 0 :(得分:4)

为什么不使用前导位以外的下两位。您可以先将数字划分为8 bin,然后将接下来的两位进一步划分为4。在这种情况下,您可以使用非常快速的简单移位操作。

编辑:如果您认为使用对数是一个可行的解决方案。这是一般算法:

a为对数的基数,范围为(b_min, b_max) = (32,8191)。您可以使用以下公式找到基数:

log(b_max/b_min) / log(a) = 32 bin

给你a~1.1892026。如果您使用此a作为对数的基数,则可以将范围(b_min, b_max)映射到(log_a(b_min), log_a(b_max)) = (20.0004,52.0004)

现在您只需要用20.0004减去所有元素即可获得范围(0,32)。它保证所有元素都是对数均匀的。完成

注意:由于数字错误,元素可能会超出范围。你应该自己计算确切的值。

Note2 :log_a(b)= log(b)/ log(a)

答案 1 :(得分:2)

表查找是一个选项,该表不是那么大。如果一个8K表太大,并且你有一个计数前导零指令,你可以在前几位使用表查找。

nbits = 32 - count_leading_zeros(v)  # number of bits in number
highbits = v >> (nbits - 4)          # top 4 bits.  Top bit is always a 1.
log_base_2 = nbits + table[highbits & 0x7]

使用一些近似的log_2

填充的表格
table[i] = approx(log_2(1 + i/8.0))

如果你想保持整数运算,请将最后一行乘以一个方便的因子。

答案 2 :(得分:2)

我刚刚提出的基于IEEE 754浮点的答案:

((union { float v; uint32_t r; }){ x }.r >> 21 & 127) - 16

它将32-8192大致对数地映射到0-31(与hwlau的答案相同)。

改进版本(按位切除无用):

((union { float v; uint32_t r; }){ x }.r >> 21) - 528