将位掩码值(1,2,4,8等)映射到向量索引(1,2,3,4等)的有效方法

时间:2011-04-02 12:45:25

标签: c++ bit-manipulation

我有一组可以按位或一起使用的值:

enum EventType_e
{
    EventType_PING  = 1,
    EventType_PANG  = 2,
    EventType_PONG  = 4,
    EventType_PUNG  = 8
};

我希望这个枚举增长到最多包含15-20个项目。在接收到这些枚举值中的一个时,我希望能够将其映射到向量,但是我不想使用稀疏数组来折叠值。将1,2,4,8,16,32映射到1,2,3,4,5,6的最佳方法是什么(即在2 ^ x = 1,2 ^ x = 2,2中找到'x' ^ x = 4,2 ^ x = 8等。)

5 个答案:

答案 0 :(得分:7)

大多数现代CPU架构都有操作码来发现数字中最大或最不重要的非零位(例如,x86上的BSF and BSR)。这些也可以作为某些编译器的内在函数,例如Microsoft和Intel编译器上的_BitScanForward_BitScanReverse

上述位扫描是最快的解决方案。对于更便携的解决方案,向右移动直到钻头从末端掉落:

int i;
for (i = 0; n >>= 1; ++i) { }

请注意,这会返回0,1,2,3,这更适合于矢量索引,而不是1,2,3,4。

更复杂但更快的便携式解决方案是二进制印章:

// Logically, we initialise i to 0, and add n - 1 at the end. Initialising
// to -1 avoids the subtraction. This is splitting hairs somewhat, and who
// knows — initialising to -1 instead of zero might be slow!
int i = -1;
if (n >> 16) { n >>= 16; i += 16; }
if (n >>  8) { n >>=  8; i +=  8; }
if (n >>  4) { n >>=  4; i +=  4; }
if (n >>  2) { n >>=  2; i +=  2; }
i += n;

答案 1 :(得分:3)

“查找x”的函数称为对数。在这种情况下log2。整数没有标准的C log2函数,计算是一个小循环。根据您的体系结构,您的cpu可能有一个asm指令来获取最高位,这也是相同的。

在我看来,更好的解决方法就是反过来。

定义类似

的内容
#define PING 1
#define PANG 2
#define PONG 3
#define PUNG 4

(你也可以在这里使用枚举)。

然后在你的活动中点击类似

的内容
EventType_PING 1 << PING,
EventType_PANG 1 << PANG,
EventType_PONG 1 << PONG,
EventType_PUNG 1 << PUNG,

答案 2 :(得分:1)

您想使用binary logarithm

#include <cmath>
double power = log2n(number);

答案 3 :(得分:1)

如果枚举值为2的幂,那么我订阅已经建议log2的答案(他们打败了我)但是“建议”你使用一些“花哨的”Bit Twiddling Hacks(查看部分找到记录整数2的基数。

答案 4 :(得分:1)

你基本上要求的是:“如果存储在整数X中的2的幂,找到指数E的最有效方法是什么?”

简单的方法是搜索那个重要的非零位:

int E = 0;
while (X >>= 1)
    E++;

请注意,这会为E = 0输出X = 1 - 您可能需要将E初始化为1E = 1X = 1