Ego*_*gon 9 performance bit-manipulation logarithm bitcount micro-optimization
获得数字的基数2对数的最佳解决方案是什么,我知道它是2的幂(2^k).(当然,我知道只有价值2^k不k本身).
我想做的一种方法是减去1然后做一个bitcount:
lg2(n) = bitcount( n - 1 ) = k, iff k is an integer
0b10000 - 1 = 0b01111, bitcount(0b01111) = 4
Run Code Online (Sandbox Code Playgroud)
但有没有更快的方法(没有缓存)?还有一些不涉及bitcount的事情会很快知道吗?
其中一个应用是:
suppose you have bitmask
0b0110111000
and value
0b0101010101
and you are interested of
(value & bitmask) >> number of zeros in front of bitmask
(0b0101010101 & 0b0110111000) >> 3 = 0b100010
this can be done with
using bitcount
value & bitmask >> bitcount((bitmask - 1) xor bitmask) - 1
or using lg2
value & bitmask >> lg2(((bitmask - 1) xor bitmask) + 1 ) - 2
Run Code Online (Sandbox Code Playgroud)
对于它比快位计数没有缓存应该是快于O(lg(k))地方k是存储位的数量.
是.lg(n)如果你知道有问题的整数是2的幂,这里有一种没有bitcount的方法.
unsigned int x = ...;
static const unsigned int arr[] = {
// Each element in this array alternates a number of 1s equal to
// consecutive powers of two with an equal number of 0s.
0xAAAAAAAA, // 0b10101010.. // one 1, then one 0, ...
0xCCCCCCCC, // 0b11001100.. // two 1s, then two 0s, ...
0xF0F0F0F0, // 0b11110000.. // four 1s, then four 0s, ...
0xFF00FF00, // 0b1111111100000000.. // [The sequence continues.]
0xFFFF0000
}
register unsigned int reg = (x & arr[0]) != 0;
reg |= ((x & arr[4]) != 0) << 4;
reg |= ((x & arr[3]) != 0) << 3;
reg |= ((x & arr[2]) != 0) << 2;
reg |= ((x & arr[1]) != 0) << 1;
// reg now has the value of lg(x).
Run Code Online (Sandbox Code Playgroud)
在每个reg |=步骤中,我们连续测试以查看是否有任何位x与交替位掩码共享arr.如果是这样,这意味着lg(x)具有在该位掩码位,我们有效地补充2^k到reg,这里k是交替位掩码长度的记录.例如,0xFF00FF00是8个1和0的交替序列,因此该位掩码k为3(或lg(8)).
基本上,每个reg |= ((x & arr[k]) ...步骤(和初始分配)都会测试是否设置了lg(x)位k.如果是这样,我们将其添加到reg; 所有这些位的总和将是lg(x).
这看起来很多魔术,所以让我们试一试.假设我们想知道值2,048的2的幂是多少:
// x = 2048
// = 1000 0000 0000
register unsigned int reg = (x & arr[0]) != 0;
// reg = 1000 0000 0000
& ... 1010 1010 1010
= 1000 0000 0000 != 0
// reg = 0x1 (1) // <-- Matched! Add 2^0 to reg.
reg |= ((x & arr[4]) != 0) << 4;
// reg = 0x .. 0800
& 0x .. 0000
= 0 != 0
// reg = reg | (0 << 4) // <--- No match.
// reg = 0x1 | 0
// reg remains 0x1.
reg |= ((x & arr[3]) != 0) << 3;
// reg = 0x .. 0800
& 0x .. FF00
= 800 != 0
// reg = reg | (1 << 3) // <--- Matched! Add 2^3 to reg.
// reg = 0x1 | 0x8
// reg is now 0x9.
reg |= ((x & arr[2]) != 0) << 2;
// reg = 0x .. 0800
& 0x .. F0F0
= 0 != 0
// reg = reg | (0 << 2) // <--- No match.
// reg = 0x9 | 0
// reg remains 0x9.
reg |= ((x & arr[1]) != 0) << 1;
// reg = 0x .. 0800
& 0x .. CCCC
= 800 != 0
// reg = reg | (1 << 1) // <--- Matched! Add 2^1 to reg.
// reg = 0x9 | 0x2
// reg is now 0xb (11).
Run Code Online (Sandbox Code Playgroud)
我们看到最终值reg是2 ^ 0 + 2 ^ 1 + 2 ^ 3,实际上是11.
如果你知道数字是2的幂,你可以直接向右移动(>>)直到它等于0.你向右移动的次数(减去1)就是你的k.
编辑:比这更快的是查找表方法(虽然你牺牲了一些空间,但不是一吨).请参阅http://doctorinterview.com/index.html/algorithmscoding/find-the-integer-log-base-2-of-an-integer/.
| 归档时间: |
|
| 查看次数: |
593 次 |
| 最近记录: |