位运算
先来谈谈位运算背景:
在现代计算机中所有的数据都是以二进制的形式存储在设备中。即0、1两种状态,计算机对二进制数据进行的运算(+、-、*、/)都是叫位运算,即将符号位共同参与运算的运算。位运算就是直接对整数在内存中的二进制位进行操作。
我们来一一介绍下有哪几种位运算符:(上面是A,下面是B,拿 8 位举例)
- 按位与( & )
对两个数进行操作,然后返回一个新的数,这个数的每个位都需要两个输入数的同一位都为1时才为1,如下图:
A:1111 1100
B:0011 1111
(A & B) 结果为 60 , 二进制为 0011 1100
- 按位或( | )
比较两个数,然后返回一个新的数,这个数的每一位设置1的条件是两个输入数的同一位都不为0(即任意一个为1,或都为1),如下图:
A:1011 0010
B:0101 1110
(A | B) 结果为 254 , 二进制为 1111 1110
- 按位异或( ^ )
比较两个数,然后返回一个数,这个数的每个位设为1的条件是两个输入数的同一位不同,如果相同就设为0,如下图:
A:0001 0100
B:0000 0101
(A ^ B) 结果为 17 , 二进制为 0001 0001
- 按位取反( ~ )
对一个操作数的每一位都取反,如下图:
A:0000 1111 ,十进制为:15
(~A ) 结果为 240 , 二进制为 1111 0000
- 按位左移( << )
将操作数的所有位向左移动指定的位数。
下图展示了11111111 << 1(11111111 左移一位)的结果。
蓝色数字表示被移动位,灰色表示被丢弃位,空位用橙色的0填充。
A:1111 1111 ,十进制为:255
(A << 1)结果为 254 , 二进制为 1111 1110
- 按位右移( >> )
将操作数的所有位向又移动指定的位数。
下图展示了11111111 >> 1(11111111 右移一位)的结果。蓝色数字表示被移动位,灰色表示被丢弃位,空位用橙色的0填充。右移对于无符号类型强制补0,对于有符号类型续补符号位
A:1111 1111 , 十进制为:255
A >> 1 结果为 126 , 二进制为 0111 1111 - 无符号右移( >>> )(没有无符号左移( <<< ))
无符号右移,忽略符号位,空位都以0补齐
>>>与>>唯一的不同是它无论原来的最左边是什么数,统统都用0填充。
以上就是位运算的运算符。
下面我们来聊一下,
Java高性能运算之对于乘法的优化
我们都知道位运算是公认的高效运算,Java对于数值非常大的数做乘法依然处理的很快,这是因为做了位运算优化。
我们先来举个例子:
对十进制数:90,做位运算 90 << 3,结果应该是多少?
答案肯定是:90000,即 90 * 10^3.
那么对于二进制数也是如此,
int a = 90;
a = a << 3;
System.out.println(a);
运行结果:
720
90在计算机中以二进制形式存储,左移 3 位,就相当于 90 * 2^3 = 720.
那么回到Java乘法优化这里,
123 * 237
=123 * 128 + 123 * 64 + 123 * 32 + 123 * 8 + 123 * 4 + 123 * 1
=123 << 7 + 123 << 6 + 123 << 5 + 123 << 3 + 123 << 2 +123
这样算起来是不是就要快了许多。
对于乘法和以及%运算,JVM一定会优化,这些是不需要程序员去考虑的,直接去用 * 、% 即可。
参考链接:https://jingyan.baidu.com/article/1612d5008ff5b7e20f1eee4c.html