位运算实用技巧(Java实现)

1. Java支持的位运算符:

&:按位与

|:按位或

~:按位非(Esc下面那个键)

^:按位异或

<<:左位移运算符

>>:有符号右位移运算符

>>>:无符号右位移运算符

因为Java在表示二进制数时采用的是补码(2's complement)的形式,最高位为符号位,即负数为1,非负数为0。

无符号右位移运算会直接在高位补0,而有符号右位移运算符会根据当前符号位的数字决定高位补0或1以保证结果正负性不变。

2.位运算小技巧

1).求整数m与2的n次幂的乘积,即m*(2^n)

可直接使用 m<<n 获得结果,如:

int a = 7<<2            //a = 7*(2^2) = 7*4 = 28

int b = 6<<1            //b = 6*(2^1) = 6*2 = 12

注意,任何数左(右)位移32位或32的整数倍位所得的结果与原数字相同

2).求整数m对2的n次幂取余的结果,即m%(2^n)

可直接使用 m&((1<<n)-1) 获得结果,如:

int a = 19&((1<<4)-1)            //a = 19%(2^4) = 19%16 = 3

3).判断整数m的奇偶性,即m%2==1?奇数:偶数

可直接使用 (m&1)==1?奇数:偶数 获得结果,如:

boolean a = (3&1)==1              //true

boolean b = (4&1)==1            //false

4).不用临时变量交换两个整数的值

连续使用三次异或,获得结果,如:

int a = 3, b = 4

a = a^b

b = a^b        // b = 3

a = a^b        // a = 4

原理:

异或0具有保持的特点,即1010^0000 = 1010;

异或1具有翻转的特点,即1010^1111 = 0101;

由此可推导:

b^(a^b) = a

a^(b^(a^b)) = b

5).取整数m的绝对值,即Math.abs(m)

可直接使用 (m^(m>>31))-(m>>31) 获得结果,如:

int a = (-3^(-3>>31))-(-3>>31)        //a=3

int b = (5^(5>>31))-(5>>31)        //b=5

原理:

m>>31可取出整数m的最高位,即符号位。

若符号位为0,则m为非负数,m异或0,m不变,再减去0,m仍不变

若符号位为1,则m为负数,m异或1,m每位翻转,再减去1,根据补码的定义,负数m变为正数-m

6).将二进制码右数第一个1输出

直接通过 a&(~a)获得结果,原理如下:

a = 00110100

~a = 11001011

-a = 11001100

a & -a = 00000100

「-a」其实是个算术运算,它等于把 a 取反再加 1。观察上面的例子,~a 的各位均与 1 相反,给它加上 1,会导致一系列进位,使得从最低位开始的一串 1 变成 0,而这一串 1 前面的 0 变成 1。比较 a 与 -a 可以发现,它们有且仅有一位同时为 1,而这个 1 恰好是 a 中最右边一个 1 的位置,于是 a & -a 就可以把这个 1 提取出来了。

7).从最低位遍历二进制码中所有的1

在6).的基础上每次取出1后通过异或将该位置0,即可取出下一个1。注意这个过程会改变a的值。

while (a != 0){

    p = a & -a

    a ^= p

    Do something with p

}

8).判断二进制码中1的个数的奇偶性

你能看出这个代码的原理吗?

  x ^= (x >>> 1);

  x ^= (x >>> 2);

  x ^ =(x >>> 4);

  x ^= (x >>> 8);

  x ^= (x >>> 16);

    为了说明上面这段代码的原理,我们拿数字1314520出来说事。1314520的二进制为101000000111011011000,第一次异或操作的结果如下:

    00000000000101000000111011011000

^    0000000000010100000011101101100

—————————————

    00000000000111100000100110110100

    得到的结果是一个新的二进制数,其中右起第i位上的数表示原数中第i和i+1位上有奇数个1还是偶数个1。比如,最右边那个0表示原数末两位有偶数个1,右起第3位上的1就表示原数的这个位置和前一个位置中有奇数个1。对这个数进行第二次异或的结果如下:

    00000000000111100000100110110100

|      000000000001111000001001101101

—————————————

    00000000000110011000101111011001

    结果里的每个1表示原数的该位置及其前面三个位置中共有奇数个1,每个0就表示原数对应的四个位置上共偶数个1。一直做到第五次异或结束后,得到的二进制数的最末位就表示整个32位数里有多少个1,这就是我们最终想要的答案。

9).计算二进制码中的1的个数

本条参考:https://www.douban.com/note/274239939/

    同样假设x是一个32位整数。经过下面五次赋值后,x的值就是原数的二进制表示中数字1的个数。比如,初始时x为1314520,那么最后x就变成了9,它表示1314520的二进制中有9个1。

x = (x & 0x55555555) + ((x >>> 1) & 0x55555555);

x = (x & 0x33333333) + ((x >>> 2) & 0x33333333);

x = (x & 0x0F0F0F0F) + ((x >>> 4) & 0x0F0F0F0F);

x = (x & 0x00FF00FF) + ((x >>> 8) & 0x00FF00FF);

x = (x & 0x0000FFFF) + ((x >>> 16) & 0x0000FFFF);

    为了便于解说,我们下面仅说明这个程序是如何对一个8位整数进行处理的。我们拿数字211来开刀。211的二进制为11010011。

+—+—+—+—+—+—+—+—+

| 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 |  <—原数

+—+—+—+—+—+—+—+—+

|  1 0  |  0 1  |  0 0  |  1 0  |  <—第一次运算后

+——-+——-+——-+——-+

|    0 0 1 1    |    0 0 1 0    |  <—第二次运算后

+—————+—————+

|        0 0 0 0 0 1 0 1        |  <—第三次运算后,得数为5

+——————————-+

    整个程序是一个分治的思想。第一次我们把每相邻的两位加起来,得到每两位里1的个数,比如前两位10就表示原数的前两位有2个1。第二次我们继续两两相加,10+01=11,00+10=10,得到的结果是00110010,它表示原数前4位有3个1,末4位有2个1。最后一次我们把0011和0010加起来,得到的就是整个二进制中1的个数。程序中巧妙地使用取位和右移,比如第二行中$33333333的二进制为00110011001100….,用它和x做and运算就相当于以2为单位间隔取数。shr的作用就是让加法运算的相同数位对齐。

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

推荐阅读更多精彩内容

  • Win7下如何打开DOS控制台? a:开始--所有程序--附件--命令提示符 b:开始--搜索程序和文件--cmd...
    逍遥叹6阅读 1,599评论 4 12
  • 1 关键字 1.1 关键字的概述 Java的关键字对java的编译器有特殊的意义,他们用来表示一种数据类型,或...
    哈哈哎呦喂阅读 654评论 0 0
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,631评论 18 399
  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,745评论 0 33
  • 空旷的教室 那么明亮 柔美的晚灯 抚慰人的心房 端坐在教室一隅 冷却心中的念想 未几,未几 有人询事,无人问伤 蜷...
    RMwang阅读 387评论 0 0