写在前面
一直以来对二进制的操做计算不太清楚,此次找了一些资料完整地进行了一些总结。html
1、进制类别和关系:
- 二进制,十进制,十六进制的区别和进制之间的相互转换方法(概念性的东西,能够百度)。
- n位的二进制可以表示2的n次方个数,如4位的二进制能够表示十进制的0~15共16个数 。
- 十六进制的基数是16,数码为0、一、二、三、四、五、六、七、八、九、A、B、C、D、E、F,其中用A,B,C,D,E,F(字母不区分大小写)这六个字母来分别表示10,11,12,13,14,15。
- 因为十六进制的基数是2的幂,所以二进制和十六进制的转换很方便。一个二进制数,只要把它从低位到高位每4位组成一组,4个二进制位能够表示从0到15的数字,这恰好是1个16进制位能够表示的数据,也就是说,将二进制转换成十六进制只要每4位进行转换就能够了。
- 0011 0101 1011 1111 = 0x35BF(以0x开始的数据表示16进制) 。
- MIN_VALUE = 0x80000000对应的二进制是10000000 00000000 00000000 00000000
- MAX_VALUE = 0x7fffffff对应的二进制是01111111 11111111 11111111 11111111
2、移位操做
- 左移位<< :
/* 00000001 << 1 = 00000010 */
1 << 1 == 2
/* 00000001 << 3 = 00001000 */
1 << 3 == 8
复制代码
- 右移位>> :
向右移位是有符号操做符。和许多语言同样,Java使用最高位来表示数值的正负,负数的最高位永远为1。一个以1开头的二进制数移位后还将以1开头,一个以0开头的二进制数移位后还将以0开头。
/* 11111111 11111111 11111111 11110000 >> 4 = 11111111 11111111 11111111 11111111 */
0xFFFFFFF0 >> 4 == 0xFFFFFFFF
/* 00001111 11111111 11111111 11111111 >> 4 = 00000000 11111111 11111111 11111111 */
0x0FFFFFFF >> 4 == 0x00FFFFFF
复制代码
- 无符号右移>>> :这种移位会忽略符号位并老是用“0”来填充。
/* 10000000 00000000 00000000 00000000 >>> 1 = 01000000 00000000 00000000 00000000 */
0x80000000 >>> 1 == 0x40000000
复制代码
- 移位的做用
- 迅速求2的幂。1向左移位1位是2,移2位是4,移3位是8…… 类似的,向右移1位至关因而把该数除以2。(将一个数k移动n位,能够看作将k*2^n)
- 建立掩码。位掩码可用于屏蔽或者修改一个二进制数中的某些指定位。如获得00001000的掩码能够经过1 << 3获得。
3、位运算操做符
- ~ :按位取反,若是位为0,结果是1,若是位为1,结果是0
~1111 == 0000
~0011 == 1100
复制代码
- & : 按位与,两个操做数中位都为1,结果才为1,不然结果为0
1010 & 0101 == 0000
1100 & 0110 == 0100
复制代码
- ^ : 按位异或,两个操做数的位中,相同则结果为0,不一样则结果为1
1010 ^ 0101 == 1111
1100 ^ 0110 == 1010
复制代码
- | : 按位或,两个位只要有一个为1,那么结果就是1,不然就为0
1010 | 0101 == 1111
1100 | 0110 == 1110
复制代码
- 位运算符的做用:
- 能够选择性的把一个二进制数的某位设为0,让数与一个全1可是某位为0的数相与。如,01010101 & ~(1<<2) == 01010101 & 11111011 == 01010001
4、原码, 反码, 补码:
对于一个数, 计算机要使用必定的编码方式进行存储。原码,反码,补码是机器存储一个具体数字的编码方式。java
- 机器数和真值
- 机器数:一个数在计算机中的二进制表示形式,叫作这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1。如,00000011 和 10000011这两个机器数分别表示+3和-3。
- 真值:将带符号位的机器数对应的真正数值称为机器数的真值。如,10000011其最高位 1 表明负,其真正数值是 -3而不是形式值131(10000011转换成十进制等于131)。
- 原码:符号位加上真值的绝对值, 即用第一位表示符号, 其他位表示值.如,[+1]原 = 0000 0001,[-1]原 = 1000 0001
- 由于第一位是符号位, 因此 8 位二进制数的取值范围是:[1111 1111 , 0111 1111] 即 [-127 , 127]
- 原码是人脑最容易理解和计算的表示方式.
- 反码:正数的反码是其自己,负数的反码是在其原码的基础上,符号位不变,其他各个位取反。如,[+1] = [00000001]原 = [00000001]反 / [-1] = [10000001]原 =[11111110]反
- 若是一个反码表示的是负数,人脑没法直观的看出来它的数值.一般要将其转换成原码再计算.
- 补码:正数的补码就是其自己,负数的补码是在其原码的基础上,符号位不变,其他各位取反, 最后 +1. (即在反码的基础上 +1)
- 对于负数, 补码表示方式也是人脑没法直观看出其数值的。一般也须要转换成原码再计算其数值。
- 为什么要使用反码和补码
- 设计简单:由于人脑能够知道第一位是符号位,在计算的时候咱们会根据符号位,选择对真值区域的加减。可是对于计算机,加减乘数是最基础的运算,要设计地尽可能简单。而让计算机辨别"符号位"会让计算机的基础电路设计变得十分复杂。
- 加法设计:能够用符号位参与运算来简化设计。根据运算法则减去一个正数等于加上一个负数, 即: 1-1=1+(-1)=0,因此机器能够只有加法而没有减法,这样计算机运算的设计就更简单了。
- 原码直接符号位相加,获得的结果是错误的,所以须要使用反码和补码
- 反码加法:
反码加法结果的真值部分是正确的,可是在"0"这个特殊的数值上,虽然人们理解上 + 0和 -0 是同样的, 可是 0 带符号是没有任何意义的, 并且会有 [0000 0000]原和[1000 0000]原两个编码表示 0。
// 计算十进制的表达式: 1 - 1 = 0
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
复制代码
- 补码加法:
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
复制代码
- 这样 0 用 [0000 0000] 表示,而反码出现问题的-0则不存在了,并且能够用多余的[1000 0000] 表示 -128:
(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补
复制代码
- 在用补码运算的结果中,[10000000]补就是-128,可是注意由于其实是使用之前的-0的补码来表示 -128, 因此 -128并无原码和反码表示(对-128的补码表示[10000000]补算出来的原码是[0000 0000], 这是不正确的)
- 使用补码运算可以多表示一个最低数,这就是为何8位二进制,使用原码或反码表示的范围为 [-127, +127], 而使用补码表示的范围为 [-128, 127]。
5、Integer的MIN_VALUE和MAX_VALUE
- 计算机存储数字是使用补码, 因此对于编程中经常使用到的 32 位int类型,能够表示范围是: [-2^31, 2^31-1] 由于第一位表示的是符号位,而使用补码表示时又能够多保存一个最小值。
- 从表示的数字总数来讲,仍是 2^31*2(由于正负值,因此*2)
- 对于正数的2^31来讲,[00000000 00000000 00000000 00000000]表示了0,因此正数的最大值是2^31-1(由于一种排列一个数,数与数之间都是隔1,因此正数总数-1即正数的最大值)。
- 对于负数的2^31来讲,[10000000 00000000 00000000 00000000]表示了最大值,因此负数的最大值是-2^31,多表示了一个数。
- Integer.MAX_VALUE,即2^31-1=2147483647,最小值为-2^31=Integer.MIN_VALUE -2147483648
- 越界问题
- Integer.MIN_VALUE-1 = Integer.MAX_VALUE:
Integer.MIN\_VALUE - 1 = Integer.MIN_VALUE + (-1)
10000000000000000000000000000000
+ 11111111111111111111111111111111[补]
---------------------------------------------------
1,01111111111111111111111111111111[补]
舍弃最高位的进位,因此获得的就是Integer.MAX_VALUE
复制代码
- Integer.MAX_VALUE + 1= Integer.MIN_VALUE:
对Integer.MAX_VALUE加1,2147483648(越界了),结果是-2147483648,便是Integer.MIN_VALUE。
01111111111111111111111111111111
+ 00000000000000000000000000000001[正数补码等于自己]
---------------------------------------------------
10000000000000000000000000000000[补]
复制代码
- 对Integer.MIN_VALUE取绝对值:
由于值为-2147483648,绝对值2147483648超过Integer.MAX_VALUE 2147483647,因此值仍是Integer.MIN_VALU。由于,Integer.MAX_VALUE=01111111111111111111111111111111,再加1为10000000000000000000000000000000,等于Integer.MIN_VALUE
4、Java中的方法
- java代码里操做二进制数字的方法是使用Integer.parseInt()方法。如,Integer.parseInt(“101″,2)表明着把二进制数101转换为十进制数5。
5、参考资料
文章一、 文章二、 文章三、 文章四、 文章五算法