神奇的二进制

(在计算机中,数都是二进制来存储的,所以二进制的一些运算要比普通的等价运算(+,-,*,/)更快,更简单,所以知道他们的技巧显得尤其重要!)

异或运算:

首先 异或(^) 表示当两个数的二进制表示,进行异或运算时,当前位的两个二进制表示不同则为 1 相同则为 0 .该方法被广泛推广用来统计一个数的1的位数!

所以二进制中 对应二进制位数进行异或操作时, 与0异或对应该二进制位数值不变, 与 1 异或时对应该二进制位数值相反(即 1 变成 0 , 0 变成 1).

参与运算的两个值,如果两个二进制相应位相同,则结果为0,否则(不同)为1。
即:
  0^0 = 0,
  1^0 = 1,
  0^1 = 1,
  1^1 = 0

按位异或的3个特点:
(1) 00=0,01=1 0异或任何数=任何数 (这里的任何数是指二进制位上的那个数,即任何数要么为0 ,要么为1 .)
(2) 10=1,11=0 1异或任何数-任何数取反 (同理)
(3) 任何数异或自己=把自己置0

按位异或的几个常见用途:
(1) 使某些特定的位翻转
例如对数10100001的第2位和第3位翻转(不管是0 还是 1 都可以,因为上面也说了 任何数与1 异或 任何数取反 ! 所以可以进行翻转!),则可以将该数与00000110进行按位异或运算

10100001^00000110 = 10100111

(2) 实现两个值的交换,而不必使用临时变量。
例如交换两个整数a=10100001,b=00000110的值,可通过下列语句实现:
    a = a^b;   //a=10100111
    b = b^a;   //b=10100001
    a = a^b;   //a=00000110
(一句话: a=ab(b=a) ; )

再次 & (与) 二进制对应位上都是 1 结果才是1 . 否则就是 0 . (和电路开关很像,串联,同时开才开,否则就是关.)

技巧 1 : 把一个整数减去1,再和原整数做与运算,会把该整数的二进制中的最右边一个1变成0 , 那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作.

技巧 2 : 二进制的最低位是1就是奇数,是0就是偶数.
(原因 : 二进制的位数(由低到高)分别代表着1,2,4,8,16,32,64,128,256,512,1024.只有最低位的这个是1或0,所以二进制最低位为1时,就是奇数(偶数由上面的这些基本的组成嘛!) )

技巧 3 :算一个数的二进制最低位是多少, 直接 x&1 = x的最低位是多少.

例 1: 如何用一条语句表示判断一个整数是不是2的整数次方.
解 : 因为是整数次方,所以该数的二进制中必定只含一个 1 . 所以结合上面的技巧,就有 !(x & (x-1) ) ;

例 2 : 写一个函数,判断一个数的二进制中多少个 1 .

int check(int x)
{
    int num=0;
    while(x)
    {
        x &= (x-1);
        num++;
    }
    return num;
}

例 3 : 输入两个整数m和n,计算需要改变m的二进制表示中的多少位才能得到n .
思路: 结合异或的性质运算,首先让 m^n 得到一个数,则这个数二进制中有多少个1 , 则m,n就有多少位不同.所以统计得到的这个数中又多少个1就行了.

int check(int m,int n)
{
    int x=m^n;
    int num=0;
    while(x)
    {
        x &= (x-1);
        num++;
    }
    return num;
}

例 4:判断一个数的奇偶性(结合技巧)

     if(x&1)
        是奇数.
     else 
       是偶数.

例 5 :算一个数二进制的补位数(比如说5的二进制是101, 所以补位数就是010, 即2,当然不能直接用~)

int sum=0,s=1;
while(t){
        int m=((t&1)^1);
        sum += s*m;   //是1才算值, 是零就不管.
        t  >>= 1;   //不断除二.
        s <<= 1;  //s表示2的几次方.
}

二进制的一些操作:

1:将一个十进制的数分解为二进制表示. 
while(t){
        int m=t&1;
        a[k++]=m;
        t >>= 1;
}
2:将一个十进制数转化成二进制的同时再算出转化后的这个数十进制表示为多少.
int s=1,sum=0;
while(t){
        int m=t&1;
        sum += s*m;
        s <<= 1;
        t >>= 1;
}
3:取某个数的第 i 个 二进制位数.
int Getbit(int x,int i)
{
    return (x >> i) & 1;
}
4:把  x  的第 i 位设置成 v .
void setbit(int & x,int i,int v)   //这样引用的话,形参改变对应实参也会改变.
{
    if(v ){
        c |= (1 << i);  
   }
    else
        c &= ~(1 << i);
}
5:把x的第 i 位翻转.(1 翻为0 , 0 翻为 1).
void flipbit(char & c ,int i)
{ 
    c ^= (1 << i) ;
}
一大波操作 : 
去掉最后一位          |(101101->10110) |               x >> 1
在最后加一个0        |(101101->1011010) |            x < < 1
在最后加一个1        |(101101->1011011) |            x < < 1+1
把最后一位变成1     |(101100->101101) |              x | 1
把最后一位变成0     |(101101->101100) |              x | 1-1
最后一位取反          |(101101->101100) |             x ^ 1
把右数第k位变成1    | (101001->101101,k=3) |      x | (1 < < (k-1))  //k>=1, 即第一位算的是1
把右数第k位变成0    | (101101->101001,k=3) |      x & ~ (1 < < (k-1))
右数第k位取反        | (101001->101101,k=3) |       x ^ (1 < < (k-1))
取末三位               | (1101101->101) |                x & 7
取末k位                | (1101101->1101,k=5) |        x & ((1 < < k)-1)
取右数第k位           | (1101101->1,k=4) |             x >> (k-1) & 1
把末k位变成1         | (101001->101111,k=4) |       x | (1 < < k-1)
末k位取反              | (101001->100110,k=4) |      x ^ (1 < < k-1)
把右边连续的1变成0     | (100101111->100100000) |   x & (x+1)
把右起第一个0变成1     | (100101111->100111111) |   x | (x+1)
把右边连续的0变成1     | (11011000->11011111) |      x | (x-1)
取右边连续的1        | (100101111->1111) |           (x ^ (x+1)) >> 1
去掉右起第一个1的左边 | (100101000->1000) |       x & (x ^ (x-1))
判断奇数                   (x&1)==1
判断偶数                    (x&1)==0 
取右边第一个1所在位置  x&-x
将右边第一个1变为0.   x &= (x-1)
 
移位运算要点 
1:  它们都是双目运算符,两个运算分量都是整形,结果也是整形。  
2:  "<<" 左移:右边空出的位上补0,左边的位将从字头挤掉,其值相当于乘2。  
3:  ">>"右移:右边的位被挤掉。对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或补1,这取决于所用的计算机系统。  
4:  ">>>"运算符,右边的位被挤掉,对于左边移出的空位一概补上0。
位运算符的应用 (源操作数s 掩码mask)
(1) 按位与-- &
1: 清零特定位 (mask中特定位置0,其它位为1,s=s&mask)
2: 取某数中指定位 (mask中特定位置1,其它位为0,s=s&mask)

(2) 按位或-- |  
     常用来将源操作数某些位置置为1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)
(3) 位异或-- ^1 
1: 使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask)
2: 不引入第三变量,交换两个变量的值(a = a^b^(b==a); || a ^= b;  b ^= a;  a ^= b;)

二进制补码运算公式:(不懂负数的点击最下方)
-x = ~x + 1 = ~(x-1)  
~x = -x-1 
-(~x) = x+1
~(-x) = x-1
比较应用举例
(1)整数的平均值对于两个整数x,y,如果用 (x+y)/2 求平均值,会产生溢出,因为 x+y 可能会大于INT_MAX,
但是我们知道它们的平均值是肯定不会溢出的,我们用如下
int average(int x, int y) //返回X,Y 的平均值
{     
         return (x&y)+((x^y)>>1);
}
(2) x 的 相反数 表示为 (~x+1) 

不懂负数在计算机中如何用二进制表示的请点这里

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

推荐阅读更多精彩内容

  • 网站乱码问题我们会经常碰到,大多见于非英文的中文字符或其他字符乱码,而且,这类问题常常是因为编码方式问题,主要原因...
    波段顶底阅读 2,808评论 1 9
  • 位运算 位运算的运算分量只能是整型或字符型数据,位运算把运算对象看作是由二进位组成的位串信息,按位完成指定的运算,...
    IIronMan阅读 7,723评论 0 2
  • I:一个人走得很快,一群人走得很远。信息化的时代,人们开始孤立起来,一个人一部手机就是全世界。我们不去交流分享,大...
    berryl丽阅读 165评论 1 2
  • 尚未开始
    晓兮悠然阅读 142评论 0 0
  • 现在的社会变化的确实太快,对于我们这些80后都感觉到紧迫,而对于父辈人来说这个社会已经变的他们已经都不认识...
    救赎的公牛阅读 114评论 0 0