美文网首页程序员
位运算实用技巧(Java实现)

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

作者: Omega_Ariston | 来源:发表于2017-10-22 18:37 被阅读137次

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的作用就是让加法运算的相同数位对齐。

相关文章

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

    1. Java支持的位运算符: &:按位与 |:按位或 ~:按位非(Esc下面那个键) ^:按位异或 <<:左位移...

  • 位运算

    (一):基础篇 Matrix67: The Aha Moments 位运算简介及实用技巧(二):进阶篇(1) 位运...

  • 2018-03-16

    JAVA - 长数据运算 使用数组实现长数据加法、乘法的简单模拟 使用数组,模拟类似竖式运算的模式,逐位进行运算与...

  • java位运算

    Java 位运算(移位、位与、或、异或、非) Java提供的位运算符有:左移( << )、右移( >> ) 、无符...

  • 集合、多线程、事件模型

    JVM内存 运算符 & 按位与 | 按位或 ~ 取反 ^ 异或 多线程实现方式 Java多线程实现方式主要有四种:...

  • python基础(四)----运算符

    一.算术运算符(基本同Java) 二.比较运算符(基本同Java) 三.赋值运算符(基本同Java) 四.位运算符...

  • JAVA位运算等运算符总结

    JAVA位运算等运算符总结 一、概述 运算符是一种“功能”符号,用以通知 Java 进行相关的运算。 Java 语...

  • java 位运算

    一、非 "~" 如果位数未0,则结果为1; 如果位数为1,则结果为0。 二、或"|" 两个只要有一个为1,结果为1...

  • Java 位运算

    首先,在Java中,运算符有以下这些: 按位与 & 按位或 | 按位异或 ^ 按位非 ~ 左移 << 右移 >> ...

  • Java位运算

    java各类转化字节数组 <----->二进制数字、十进制、16进制、字符串 二进制(Binary)<------...

网友评论

    本文标题:位运算实用技巧(Java实现)

    本文链接:https://www.haomeiwen.com/subject/sacnuxtx.html