原码,补码,反码
- 原码
用最高位的二进制位表示符号。0 = 正数,1 = 负数。
正数的原码就是其二进制位本身。
负数的源码是对应绝对值的二进制位,但是最高位变为1。
源码存在的问题是存在正0和负0的问题,虽然+0 = -0,但是它们无法在二进制表示式上统一。
同时正数和负数的加法运算不容易实现。
1 => 0 000 0001
-1 => 1 000 0001
- 反码
正数的反码就是原码。
负数的反码是将负数的符号位之外的所有比特位全部取反。
1 => 0 000 0001
-1 => 1 111 1110
- 补码
正数的补码就是原码。
负数的补码将负数的符号位之外的所有比特位全部取反,然后加1的和。
大多数计算机使用的都是补码表示法,但有过反码表示的计算机。
C语言标准没有明确规定必须使用补码表示法,Java则明确规定了必须使用补码表示法。
1 => 0 000 0001
-1 => 1 111 1111
补码完美解决和加法问题和0的统一表示问题。
基本位运算
- &(与运算)
与运算就是将两个数的补码按照二进制位(包括符号位)一次做与规则运算。
与规则是:两数同时为1返回1;否则则返回0.
0 & 0 = 0;0 & 1 = 0;1 & 0 = 0;1 & 1 = 1;
3 & 5 -> 0011 & 0101 = 0001
因此 3 & 5 = 1
- ~(取反运算)
取反运算是将这个数的补码按照二进制位(包括符号位)依次取反。
即0取反=1,1取反=0.
~(-1) = 0
~ 1 = -2
|(或运算)
或运算是将这个数的补码按照二进制位(包括符号位)做或规则运算。
或规则:两数同时为0,返回0;否则返回1.^(异或运算)
异或运算是将两个数的补码按照二进制位(包括符号位)做异或规则运算。
异或规则:
两数不同返回1,两数相同返回0.
3 ^ 5 = 6
0011 ^ 0101 = 0110
- 位移运算符号
<<(左移运算符)和<<<(无符号左移)
<<(左移运算符):
将一个数的补码,除开符号位,其余位置的数据向左依次移动。
左边溢出的数据忽略,而低位(即右边空出来的位置)数据补0.
溢出即超出这个数据类型的最大长度。
<<<(无符号左移):即连同符号位一起左移。
因为是2进制表示,所以一般而言,左移返回此数乘以2的值。
>>(右移运算符)和>>>(无符号右移)
>>(右移运算符):
将一个数的补码,除开符号位,其余位置的数据向右依次移动。
右边溢出的数据忽略,而高位(即左边空出来的位置)数据补0.
>>>(无符号右移):即连同符号位一起右移。
因为是2进制表示,所以一般而言,右移返回此数除以2的值。
常用位运算
位运算的优先级比算术运算的优先级高。
乘法和出发
一般用左/右移运算符计算以2为倍数的结果。取低位和高位
利用&运算进行取位运算。
取低位:n & 0x0000FFFF;取高位:n & 0xFFFF0000。
取低x位:n & (1 << x -1 );取x高位:n & (~(1 << x))<<(31 - x)。
这里Integer类型除开符号位,二进制值位的长度是31.正负判断
(n >>> 31) & 1,等于0为正,等于1为负。取余
n % m ,如m为2的幂次方,可用(n & (m - 1))替代。通用四则运算的实现
https://blog.csdn.net/ojshilu/article/details/11179911
注意
- 溢出
溢出是指当前值超过的其数据类型的最大和最小范围,从而使值得结果不准确。
只有当两个相同符号数相加,而运算结果的符号与原数据符号相反时,产生溢出;
其他情况,不会产生溢出。
参考
https://blog.csdn.net/coffeelifelau/article/details/52433653