最近在看recast&detour源码的时候有遇到许多数学上的算法问题,特此记录,以便以后查看。
举例:
Ilog2(8) = 3
Ilog2(15) = 3
Ilog2(16) = 4
思路:
从二进制角度看 即 右移几位 以后为1(最高位)
比如
8 = 1000b, 右移3位
15=1111b,右移3位
16=10000b,右移4位
源码:
inline unsigned int dtIlog2(unsigned int v)
{
unsigned int r;
unsigned int shift;
r = (v > 0xffff) << 4; v >>= r;
shift = (v > 0xff) << 3; v >>= shift; r |= shift;
shift = (v > 0xf) << 2; v >>= shift; r |= shift;
shift = (v > 0x3) << 1; v >>= shift; r |= shift;
r |= (v >> 1);
return r;
}
解析:
应用二分法的思想,将数进行移位。记 r 为需要右移的位数。
1)将此数与 0xffff 比较
如果比 0xffff 大,说明至少需要右移16位;r = 16(即1<<4 = 10000b);并将此数右移16位进行更新。
如果比 0xffff 小,什么都不做;r = 0。
2)将更新后的数与 0xff 比较
如果比 0xff 大,说明至少需要右移8位;r += 8(即1<<3 = 1000b);并将此数右移8位进行更新。
如果比 0xff 小,什么都不做;r += 0。
3)将更新后的数与 0xf(1111b)比较
如果比 0xf 大,说明至少需要右移4位;r += 4(即1<<2 = 100b);并将此数右移4位进行更新。
如果比 0xf 小,什么都不做;r += 0。
4)将更新后的数与 0x3(11b)比较
如果比 0x3 大,说明至少需要右移2位;r += 2(即1<<1 = 10b);并将此数右移2位进行更新。
如果比 0x3 小,什么都不做;r += 0。
5)将更新后的数(只剩下两个bit位 XXb )直接右移一位
如果结果为1,r+=1。
如果结果为0,r+=0。
r即为最终结果。
ps:此处 |= 即为 +=, 使用位运算更高效。 即 10000b | 1000b = 10000b + 1000b。