确定是否在整数数据类型中设置位的最快方法

时间:2013-08-09 07:53:37

标签: c algorithm mathematical-optimization

我有一个根据某些特定算法计算哈希值的方法。

uint8_t cal_hash(uint64_t _in_data) {
    uint8_t hash;
    // algorithm
    // bit at hash[0] = XOR of some specific bits in _in_data
    // repeat above statement for other indexed bits of hash 
    return hash;
}

我想知道在整数数据类型中访问和设置相应位的最有效方法是什么。 我已经尝试过像

这样的事情了
(((x) & (1<<(n)))?1:0)

确定任何索引处的位是1还是0。有什么比这更好的吗?

3 个答案:

答案 0 :(得分:3)

您首先要关注的是拥有正确且可移植的版本。如今,编译器将非常巧妙地优化这种位操作。

您应该始终注意您使用的掩码与您正在测试的数据类型相对应。使用intunsigned可能是不够的,因为您对uint64_t的位感兴趣并且移位超过位是未定义的行为。

在你的情况下,你可能会使用像

这样的东西
(UINT64_C(1) << (n))

用于面具。如果您想以更通用的方式执行此操作,则必须通过

之类的方式获得基本类型的1
(1 ? 1U : (X))

一起在宏

#define MASK(X, N) ((1 ? 1U : (X)) << (N))

然后测试看起来像

#define BIT(X, N) !!((X) & MASK(X, N))

答案 1 :(得分:3)

我认为这是速度与记忆类型的问题。 (更新了MrSmith42s的建议):

如果你真的想要速度,我会为每个比特定义一个掩码进行比较。也许是这样的事情:

const uint8_t BitMask[] = { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80 };

/* Find out if LSB is set */
if( hash & BitMask[0] ) { ... }

移位的问题在于它每个移位使用一条指令,而固定掩码在比较之前只有一个存储器访问。

答案 2 :(得分:2)

要查找快速设置的位,请尝试以下操作:

int oneBit = x & ~(x-1);

在此之后,oneBit将只有X集的最低位 (例如,如果x1011 0100,则oneBit将为0000 0100,例如,仅为最低位)

之后,您可以使用以下方法关闭最低位:

x &= x-1;

(例如:如果x1011 0100,则新x应为1011 0000

然后你可以重复第一个操作来找到设置的下一个最低位。

这样做有一个很大的好处,就是你不要花费时间“测试”一点只是为了找出它的零。
它可以直接找到那些设置的位,并跳过零位。

以下示例代码显示了它的实际效果:

int main(void)
{
    int x = 180;  // 1011 0100

    while (x)
    {
        printf("Low Bit is: %d\n", x & ~(x-1));
        x &= (x-1);
    }
}

输出:

Low Bit is: 4    // eg. 0000 0100
Low Bit is: 16   // eg. 0001 0000
Low Bit is: 32   // eg. 0010 0000
Low Bit is: 128  // eg. 1000 0000