本文目录
位运算
1. 简介
位运算就是直接对整数在内存中的 二进制位 进行操作。由于计算机内部就是以二进制来存储数据,位运算是相当快的运算。在现代架构中, 情况并非如此:位运算的运算速度通常与加法运算相同(仍然快于乘法运算)。
二进制位:指的是补码,而不是原码。
Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。
1.1 原码、反码及补码
- 正数:原码 = 反码 = 补码
- 负数:
- 反码 = 原码除 符号位 以外全部取反
- 补码 = 反码 + 1
2. 运算符分类
- 按位与(
&
) - 按位或(
|
) - 按位异或(
^
) - 按位取反(
~
) - 左移(
<<
) - 带符号右移(
>>
) - 无符号右移(
>>>
)(Java特有)
注:除 ~
是单目运算以外,其它均为双目运算。
3. 运算符解析
3.1 按位与( &
)
规则:如果相对应位都是 1 ,则结果为 1 ,否则为 0 。
a 00101
b 11100
& -----
r 00100
3.2 按位或(|
)
规则:如果相对应位都是 0,则结果为 0 ,否则为 1 。
a 00101
b 11100
| -----
r 11101
3.3 按位异或( ^
)
规则:如果相对应位值相同,则结果为 0 ,否则为 1 。
a 00101
b 11100
^ -----
r 11001
b 11100
^ -----
a 00101
注 :^
运算的逆运算是它本身,也就是说两次异或同一个数最后结果不变,即(a ^
b) ^
b =
a。可用于两个数的互换。
3.4 按位取反( ~
)
规则:按位取反运算符翻转操作数的每一位,即 0 变成 1 ,1 变成 0 。
a 00101
~ -----
r 11010
3.5 左移( <<
)
规则:按位左移运算符。左操作数按位左移右操作数指定的位数,空位补 0 。
a <<
b 就表示把a转为二进制后左移 b 位(在后面添 b 个 0 )。
a <<
b 的值实际上就是 a 乘以 2 的 b 次方,因为在二进制数后添一个 0 就相当于该数乘以 2 。
a 00101
b 2
<< -----
r 0010100
3.6 带符号右移( >>
)
规则:按位右移运算符。左操作数按位右移右操作数指定的位数,空位补符号位。
a >>
b 表示二进制右移b位(去掉末 b 位),相当于 a 除以 2 的 b 次方(取整)。
右移操作中右侧多余的位将会被舍弃,而左侧较为复杂:对于无符号数,会在左侧补 0;而对于有符号数,则会用最高位的数(其实就是符号位,非负数为 0,负数为 1)补齐。
a 00101
b 2
>> -----
r 00001
3.7 无符号右移(>>>
)(Java特有)
规则:按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。
a >>>
b表示二进制右移b位(去掉末b位),相当于 a 除以 2 的 b 次方(取整)。
该运算符会忽略符号位,进行右移,左侧只补 0 。
4. 复合赋值位运算符
和 +=
, -=
等运算符类似,位运算也有复合赋值运算符: &=
, |=
, ^=
, <<=
, >>=
,>>>=
。(取反是单目运算,所以没有。)
5. 优先级
位运算的优先级低于算术运算符(除了取反),而按位与、按位或及异或低于比较运算符,所以使用时需多加注意,在必要时添加括号。
6. 简单应用
6.1 判断一个数的奇偶性
利用 &
运算,来判断二进制数最后一位是 0 还是 1 。
用 a &
1 ==
0 代替 a %
2 ==
0 来判断 a 是不是偶数。
6.2 交换两个数
- 借助中间变量
- 借助累加和
- 借助
^
运算
利用 ^
运算的特性,两次异或同一个数最后结果不变。即:
a = a ^ b;
b = a ^ b;
a = a ^ b;
6.3 取余
利用 &
运算,替代 %
运算:a %
b,只针对于 b = 2n 时。
a %
b = a &
(b -
1)(b=2n),即:a %
2n =
a &
(2n -
1)
6.4 移位 == 乘除 (<< / >>>)
乘法(<<):a *
13 =
(a <<
3) +
(a <<
2) +
a
除法(>>/>>>):只有除法操作中的除数正好是一个2的n次幂时才能使用右移操作替换除法运算
6.5 判断一个整数是不是2的幂
针对于 x >
0 的整数,若结果为 0 ,即是,反之不是。即:
x && (x & (x - 1)) == 0;
6.6 取相反数
~x + 1
认真、沉着做事,每天进步一小点!!!