关于二进制
计算机中的任何数据都是二进制形式存储的,需要理解以下几个概念:
- 原码: 整数按照绝对值的大小转换成的二进制数,称为原码.负数的原码按照绝对值大小转换成的二进制数,然后最高位补1. 如: 7的原码为: 00000000 00000000 00000000 00000111, -7的原码为: 10000000 00000000 00000000 00000111
- 反码: 正数的反码与原码相同, 负数的反码是在原码的基础上除符号位外各位取反. 比如: 10000000 00000000 00000000 00000111的反码为11111111 11111111 11111111 11111000.
- 补码: 正数的补码和原码相同, 负数的补码为反码+1;比如: 10000000 00000000 00000000 00000111的补码为11111111 11111111 11111111 11111001. 负数在计算机中是以补码的形式存在的.
可以发现, 正数的原码, 反码, 补码都相同, 这些概念显然是为负数规定的. 所以补码存在的意义是什么呢?
首先要知道, 在计算机中,最大的数+1溢出为0, 根据这个知识, 假设一个正数 n,假设n占一个字节 ,
所以, 负数可以用对应的正数取反+1表示, 这就是补码.
使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。
位运算
位运算符实际上就是二进制的运算
假设数字占一个字节
- 与( & )
比如: 6 & 7
先将两个十进制的数换算成二进制:
5: 0000 0101
9: 0000 1001
然后将对应位进行与运算, 可得结果为: 0000 0001
最后再换算为十进制: 1
即 5 & 9 = 1 - 或( | )
和与运算类似, 先将两个十进制的数转换为二进制,再进行或运算.
如: 5 | 9 = 13 - 异或( ^ )
异或: 相同时是false, 不同时是 true.
如: 5 ^ 9
转换成二进制后对应位异或得: 0000 1100
所以 5 ^ 9 = 12 - 取反( ~ )
将二进制数中所有位 ( 包括符号位 ) 0变成1,1变成0. - 左移( << )
把所有位向左移动规定的位数, 低位补0.
如: 9 << 2
9的二进制: 0000 1001
得到的二进制数为: 0010 0100
其值为36
容易知道 - 右移( >> )
与左移类似, 将所有位向右移动规定的位数, 高位负数补1, 正数补0.
如: 9 >> 2
得到的二进制数: 0000 0010, 值为2
-9>>2
-9的二进制( 补码 ): 1111 0111
得到的二进制数: 1111 1101
原码为: 1000 0011, 值为-3
容易知道: - 无符号右移( >>> )
与右移的区别在于补位的时候无论正数还是负数,都补0.
位运算符的应用
使用位运算符常常可以使程序更加炫酷简洁
- 判断奇偶数
判断二进制数最后一位是0还是1
a & 1 == 0
时a为偶数 - 取余
a对 取余,可以 & 结果就是余数.
原理就是返回 位后面的数
这样取余效率高很多. - 求相反数
~a + 1 - 求绝对值
a >> 31 == 0 ? a : (~a + 1)
原理就是通过二进制的最高位判断正负.
参考:
位运算符与常用的使用场景