二进制位操作

基础概念

  • 进制
    我们日常生活中所用的多是十进制数,例如,1286是一个四位十进制数,我们可以把这个数拆开成:
    1x1000+2x100+8x10+6x1 ==>(等价于)1x103+2x102+7x101+6x100
    可以看出,十进制就是以10的幂次方为基数换算过来的,那么同理,二进制就是以2为幂次方,例如,二进制数1011换算为十进制数就是:
    1x23+0x22+1x21+1x20=11
    因为计算机的电路是只有两种状态的,所以二进制非常适合计算机使用。
  • 二进制整数
    一个字节通常来说是包括八个位的,所以,对应的二进制数位数为八,表示的范围为256:
    11111111==》1x27+1x26+1x25+....+1x20=255
    在表示有符号整数的情况下,通常将最高位表示符号位,所以此时表示的范围变为-128~127,负数时最高位为1,整数时为0.

位运算

  • 取反 ~
    取反运算符将二进制数每个位为1的变成0,为0的变成1,例如:
~ (10101)  //原值
  (01010) //取反结果值

值得注意的是取反运算不改变原变量的值,假如一个变量var,赋值为2(八位二进制中表示为00000010),于是~var的运算结果为(11111101),但是var仍为2,所以如果想使用运算后的结果,需要进行赋值,比如:

newvar=~var;
//或
var =~var;
  • 位与 :&
    二进制于运算&,会将两个操作数的二进制位逐位进行比较,相同位的值都为1时,运算结果对应位的值才为1,否则为0,例如:
  10011  //操作数1
 &10101 //操作数2
  10001 //结果
  • 位或 |
    跟位与操作类似,不过或操作只需两个比较数的对应位其中一个为1,则结果位就为1:
 1011 //操作数1
| 1101 //操作数2
  1111 //结果
  • 异或 ^
    二进制异或操作对两个操作数按位进行比较,对于结果,当两个操作数不一样时,结果位为1,如果两个操作数对应位同为0或同为1,则结果位0,例如:
  10101  //操作数1
^ 11011 // 操作数2
  01110 //结果

位操作的用法

  • 掩码
    掩码(英语:Mask)在计算机学科及数字逻辑中指的是一串二进制数字,通过与目标数字的按位操作,达到屏蔽指定位而实现需求。二进制位操作中通常使用与&操作实现掩码,我们可以定义常量MASK=2,即二进制00000010,待操作数flag=11,即00001011,那么:
    flag & MASK =>
    00000010
&   00001011
    00000010

可以看到,flag除了位1外,其他都被置0了,可以看出掩码的一个作用就是保留掩码为1 的位所对应操作数的位为1,其他位清零。

  • 打开位
    有时候我们需要将一个二进制数中的某个位置一,比如10000101中,第一位控制着硬件扬声器的开关,当我们想打开扬声器时,只需进行如下操作,假的MASK=00000010,flag=10000101,
    flag=flag | MASK
    flag就变为10000111.
  • 位关闭
    与位打开相反,位关闭操作可以将某一个位置0而不影响其他位,具体操作为
flag=flag & ~MASK
或者
flag&= ~MASK

同样,MASK保存着需要置0的位,对MASK取反就得到了一个除了待置0位为0,其他位均为1的二进制数:11111101,
然后与操作数进行与操作,就能将待置0位变成0.

  • 转置
    转置操作可以将一个为原来为0(或1)的位变为1(或0),具体操作如下:
    flag= flag ^ MASK
    MASK=00000010,flag=10000101,
  00000010
^ 10000101
  10000111
移位运算
  • 左移:<<
    左移运算将操作数按位全部往左移动对应个位,右边空出来的位用0填充,左边移出的位丢弃掉,比如:
    10001010 << 2
    00010100
    左移操作中,无符号数左移移位相当于乘以21,左移两位相当于乘上22;而对于有符号数,负数跟正数是不一样的,计算机中,负数的二进制是使用补码来表示的,最高位存放符号,正数为0,负数为1.那么什么是补码呢,举个栗子:
1000 0101 //原码,原码就是一个数的二进制表示,
          //例如这个数是-5的八位二进制表示,高位的1表示是负数
1111 1010 //反码,反码就是一个二进制数的原码,除符号位以外,其余
         // 位取反
1111 1011 //补码,补码就是在反码的基础上加1

所以,对于负数的左移,需要先求出补码,然后用补码来左移,然后再求回原码,就得出了负数左移的结果,例如:上面的-5的补码为1111 1011 ,左移一位后得1111 0110,求这个的原码得:1000 1010 ,即为-10。

  • 右移
    对于右移,由于会涉及到符号位,所以会分有符号右移和无符号右移,在java中分别用>> 和>>>符号来区分。有符号右移时,若为负数,高位将补1,无符号右移无论正负,高位均补0。例如:
    4>>2
    0000 0100 >>2 =0000 0001,结果为1;
    -4>>2
    1000 0100 >>2 ,先求反码:1111 1011 ,加1求补码:1111 1100,右移 1111 1111 ,结果数原码:1000 0001,得-1,
    对于有符号右移也是同理,只是将高位补0即可。

实战例子

在读android或java等的源码的时候,我们会看到大量的位运算操作,一开始我是一脸懵逼的,搞不清楚这是什么操作,也不懂为什么要这样操作,看到多了觉得大神都这么玩,肯定是有好处的(位操作会快很多),所以也就决定研究一下其中的原理,接下来就上面所记录的知识来写一个“源码”级别的demo,开整:
test.java

int BYTE_MASK=0xff;
long color=0x002a162f;
int blue,green,red;
red=color & BYTE_MASK;
green=(color >> 8) & BYTE_MASK;
blue =(color >> 16) & BYTE_MASK;
log.d("red="+red+" green="+green+" blue="+blue);

上面这个例子中,color存放的是一个颜色的十六进制值,这个颜色分为三原色,红绿蓝,最低位字节存放红色分量,上一个字节存放绿色分量,第三个字节放蓝色分量,BYTE_MASK作为掩码,上面有介绍过,掩码可以将自身标志位以外的位清除,所以只要用掩码和操作数进行&操作,就能提取出掩码位的数据,上面red=color & BYTE_MASK;就是将color的最后一个字节提取出来,赋值给red,然后因为绿色和蓝色分量不在最后一个字节,所以要用掩码提取,只能先进行移位操作,将对应的颜色分量移位到最后一个字节,然后进行掩码提取数值,最终将三原色分离出来。

总结

位操作不仅能装逼,还能很好的提高程序的性能,是我们进阶中高级码农的必备技能啊,在这记录下,以备岁月摧残记性。

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

推荐阅读更多精彩内容

  • 一、单位转换 在计算机科学中,bit是表示信息的最小单位,叫做二进制位;一般用0和1表示。Byte叫做字节,由8个...
    lionsom_lin阅读 1,835评论 0 1
  • 我们都知道在计算机中所有的信息最终都是以二进制的0和1来表示,而有些算法是通过操作bit位来进行运算的,这就需要我...
    geekpy阅读 78,475评论 2 10
  • 1、概念简介 子网掩码子网掩码又叫网络掩码、地址掩码,是一个32位地址,用于屏蔽IP地址的一部分以区别网络号和主机...
    黒猫阅读 7,586评论 0 23
  • 上周五下班像往常一样挤公交车,刚上车找到个扶手的地方,就听见站在我身后的小姑娘惊慌失措的声音:糟了,我的手机!上车...
    自欺欺人君阅读 217评论 3 0
  • 一年多前,参加了一次林文采老师的两天的线下课程,被她的学识、阅历、风采所折服,回来就买了一本她的书,...
    正面管教培训师阅读 1,083评论 0 1