位运算常见技巧

在新浪微博上看到一篇文章写位运算的写的很深入,文章链接见末尾,特此mark。

0.位运算的种类

符号 名称 运算规则
& 两个位都为1时,结果才为1,否则都为0
l 两个位都是0时,结果才为1,否则都为0
^ 异或 两个位都相同为0,否则为1
~ 取反 0->1,1->0
<< 左移 各二进位全部左移若干位,高位丢弃,低位补0
>> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

markdown中|我不知道怎么表示,就用l了


1.判断两个整数是否符号相反


bool oppositeSigns(int x, int y)
{
    bool f = ((x ^ y) < 0); // true iff x and y have opposite signs
    
    return f;
}

2.判断一个数的符号

bool isUnSignInt(int v){
    
    int sign;   // the result goes here
    
    // CHAR_BIT is the number of bits per byte (normally 8).
    sign = -(v < 0);  // if v < 0 then -1, else 0.
    // or, to avoid branching on CPUs with flag registers (IA32):
    sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
    // or, for one less instruction (but not portable):
    sign = v >> (sizeof(int) * CHAR_BIT - 1);
    
    return sign == 1;
}

3.求一个数的绝对值

int absulteValue(int v){

    unsigned int r;  // the result goes here
    int const mask = v >> (sizeof(int) * CHAR_BIT - 1);
    
    /*explain:在计算机中,负数以其正值的补码形式表达。
     什么叫补码呢?这得从原码,反码说起。
     原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。
     比如 00000000 00000000 00000000 00000101 是 5的 原码。
     反码:将二进制数按位取反,所得的新二进制数称为原二进制数的反码。
     取反操作指:原为1,得0;原为0,得1。(1变0; 0变1)
     比如:将00000000 00000000 00000000 00000101每一位取反,得11111111 11111111 11111111 11111010。
     称:11111111 11111111 11111111 11111010 是 00000000 00000000 00000000 00000101 的反码。
     反码是相互的,所以也可称:
     11111111 11111111 11111111 11111010 和 00000000 00000000 00000000 00000101 互为反码。
     补码:反码加1称为补码。
     也就是说,要得到一个数的补码,先得到反码,然后将反码加上1,所得数称为补码。
     比如:00000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010。
     那么,补码为:
     11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011
     所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011。转换为十六进制:0xFFFFFFFB。
     
     所以获取一个负数的绝对就是将负数取反在+1即可
     所以最初的形式可写成
     int my_abs(int a)
     {
     int i = a >> 31;
     return i == 0 ? a : (~a + 1);
     }
     
     现在再分析下。对于任何数,与0异或都会保持不变(异或是两个位相同为0,相异位1),与-1即0xFFFFFFFF异或就相当于取反。
     因此,v与mask异或后再减mask(因为mask为0或-1,所以减mask即是要么加0要么加1)也可以得到绝对值。所以可以对上面代码优化下:
     
     r = (v ^ mask) - mask;
     */
    
    
    r = (v + mask) ^ mask;
    
    //or
    //r = (v ^ mask) - mask;

    return r;
}

4.计算最大最小值

int max(int x, int y){
    
    /*
     *利用一点,对于任何数a,因为0的二进制全为0,有a&0 = 0,因为-1的二进制全为1,有a&(-1) = a
     如果x>y,x<y的值为0,-(x<y)也为0,(x ^ y) & 0 = 0, x ^ 0 = x。
     如果x<y,x<y的值为1,-(x<y)为-1,(x ^ y) & (-1) = x ^ y, x ^ (x ^ y) = y。
     于是能求得较大值。较小值类似。
     
     
     If you know that INT_MIN <= x - y <= INT_MAX, then you can use the following, which are faster because (x - y) only needs to be evaluated once.
     r = y + ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // min(x, y)
     r = x - ((x - y) & ((x - y) >> (sizeof(int) * CHAR_BIT - 1))); // max(x, y)
     */
    
    return x ^ ((x ^ y) & -(x < y));

}

5.计算一个值是否是2的次幂

bool isPowerOfTwo(int x){
    
    //如果一个数是2的次幂,那么除首位,其余为肯定都为0,减一后其余为为1
    
    bool f = x && !(x & (x - 1));
    
    return f;
}

6.交换

void swap(int &x, int &y){
    
    /*异或运算有两个特性:
    1、一个数异或本身恒等于0,如5^5恒等于0;
    2、一个数异或0恒等于本身,如5^0恒等于5。*/

    if (x != y)
    {
        x ^= y;
        y ^= x;
        x ^= y;
    }
    
}

7.更多技巧,参考文章:http://graphics.stanford.edu/~seander/bithacks.html

后面的内容没那个太深,暂时用到的可能性不太,如果后期有业余精力再去深入研究。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容