代码改变世界

位运算

2014-03-09 14:42  夜与周公  阅读(306)  评论(0编辑  收藏  举报

  有关位运算(与运算,或运算,异或运算,左移和右移)是C/C++语言偏向底层的操作。市面上有很多有关位运算的算法技巧,特在此做了整理。

  1.Bitmap

  什么事Bitmap? Bitmap的核心思想就是“索引”技术,某个比特位作为key,而该比特上的值作为value(可以理解为状态位:0 or 1)。Bitmap既然利用了索引的思想,那么Bitmap这种数据结果的核心就是如何取到某个索引(即定位到某个bit)。

  实现手段上肯定是利用位运算,如果想索引到第 i 比特,可以用如下代码:

(p + i /8) | (0x1 << (i%8)

其中8表示一个字节的比特位数,而p + i /8,表示Bitmap所在的字节,(p + i /8) | (0x1 << (i%8) 便可以索引到当前 i bit位置。使用上面的公式,Bitmap上的两个基本操作:索引和取值:

inline void SetBit(char* p, int pos)
{
    p += pos / BitSize;
    *p = *p | (0x1 << (pos % BitSize));
}

inline int Getbit(char* p, int pos)
{
    return (*(p + pos / BitSize)) | ((pos % BitSize)) ;
}

  2.计算a与b的平均值

  如何利用位运算实现求a与b的平均值呢?先看算法:

  aveg(a, b) = (a & b) + ((a^b) >> 1) 

  a & b,则取出了a与b中相同的位,a与b相同位的平均值自然是自身。a^b取出了不同的位。而不同位的平均值则需要除以2,向左移动1位即可。

  3.不使用加减法,求a与b的和

  不使用加法而实现加法?能够想到解决的方法只能是位的运算了。考察a^b:表示了没用进位的加法,而(a&b)<<1:表示加法的进位。 a^b 与 (a&b)<<1求和,则会得到想要的结果(额,求和?递归迭代完成),代码如下:

int sum(int a, int b)
{
    int sum = 0;
    int carry = 0;

    do 
    {
        sum = a ^ b;
        carry = (a & b) << 1;

        a = sum;
        b = carry;

    } while (carry);

    return sum;
}