进制
程序中的所有数在计算机内存中都是以二进制的形式储存的。位运算说穿了,就是直接对整数在内存中的二进制位进行操作。
首先呢,了解位运算之前,我们要先指定进制之间的转换
众所周知我们生活中所用的使用的数字是十进制数,而计算机所认识的是二进制
所以呢,作为一个程序员我们必须要掌握二进制与十进制之间的互转与运算
进制的相关关键字:
1)高位
一串二进制串,左面为高位
2)低位
一串二进制串,右面为低位
3)原码
我们所认识的二进制码,也就是我们进制间转换所得到的值,我们认识,但计算机不认识
4)反码
正数不需要做反码操作,,,负数的反码:符号位不变,0变1,1变0 -------反码是原码转为补码的中间过程
5)补码
计算机所认识并可计算的字节码,正数的补码还是其原码本身,,负数的补码是其反码+1
原码 ===》我们看到的
反码 ===》取反码
补码 ===》真正运行的
01.正数的原码,反码,补码都一致
02.java中所有的数字都是有符号的 符号位 正数0 负数1
03.负数的反码=符号位不变+其他位取反(1变0 0变1)
04.负数的补码=反码+1
十进制转二进制
可以明确的说,只要你会加法你就可以秒转
先来一张比较牛逼的表:
1024 512 256 128 64 32 16 8 4 2 1
看不懂?没关系,接下来我们来说
我们随便拿来一个数:765 (为了说明我这个办法确实nb,我们拿了一个比较大一点的数)
我们已经有表了,那么,就套表呗
首先找到765最近的一个比他小的数
在他下面写个1,也就是512
然后依次往后相加,发现相加比765大那么下面写0,然后舍去,只然后加下一个(注意是下面写过1的连续相加)最后可以得出来:
1024 512 256 128 64 32 16 8 4 2 1
1 0 1 1 1 1 1 0 1
765的二进制数就是0 1011111101 (最前的0当符号位)
因为是正数所以这既是它的原码也是它的补码
那如果是负数呢?-765
简单,就是拿到其正数的二进制数,改变符号位拿到原码:
1 1011111101 这个值是我们转换的二进制码
然后取反码(0变1,1变0,)
也就是 1(符号位不变) 0100000010 然后补码+1
1 0100000011
-765的补码就是1 0100000011 这个值是计算机可以进行计算解析的二进制码
二进制转十进制
可以明确的说在这里你只要会乘法运算,和明白数组下标就会秒转 或者拿出上面的万能转换表
还是老规矩,随便写一个0和1组成的字符串,然后正负两种情况
符号位为正:
随便一个0符号位的二进制串 (既是原码也是补码)
0 1101 ok,发大招,转换
先忽略符号位,将后面的二进制串我们看成一个倒着的int类型数组,低位为0,依次往做+1
古老算法:
当前数*2的下标次方,然后将所有的数相加
那么这个数就是:
1*2的0次方+1*2的2次方+1*2的3次方=1+4+8= 13
然后加上符号位
那么最终值就是+13
万能表算法:
1024 512 256 128 64 32 16 8 4 2 1
1 1 0 1
那么。。。就是 8 +4 +1=13
完美!!!
符号位为负:
如果拿到的是一个原码,,那就跟上面算法一样,只不过符号位为负的而已
如果拿到一个补码,也就是中间多两部操作
上面说了,原码转补码是 原码取反+1
那么,反推,补码转原码就是。。。补码-1取反
得到原码,再用上面其中一种算法就ok了
例子:1-2
先把3转换成二进制
00000011 (省略前24位数字 0 保留后八位)
3的二进制是 00000011
把-8转换成二进制
(注意:因为是负数 所以最高位的数字为1 则不管是反码,源码还是补码 最高位都不变都为1 )
00001000 (因为是负数 所以最高位变为1)
10001000 -8的源码
11110111 -8的反码(最高位不变 其他1变0 0变1 )
11111000 -8的补码(在反码的基础上+1)
正数的原码,反码,补码都一致 所以3的补码就是他的二进制
所以 补码-补码
00000011
+ 11111000
================
11111011 ----结果的补码
11111010 ----结果的反码 (就是在补码的基础上-1)
10000101 ----结果的源码 -5
-5(解析: 因为00000101是5的二进制 因为它的最高位是1 所以他为负数)
(结果的二进制就是00000101)
例子: 1-3
先把4转换成2进制
0 0 0 0 0 1 0 0
把-3转换成2进制
1 0 0 0 0 0 1 1 -3的源码
1 1 1 1 1 1 0 0 -3的反码(最高位不变 其他1变0 0变1 )
1 1 1 1 1 1 0 1 -3的补码(在反码的基础上+1)
0 0 0 0 0 1 0 0
+ 1 1 1 1 1 1 0 1 (1+1 进1 自己变为0 )
===============
0 0 0 0 0 0 0 1 ==== 结果的补码(00000001是1的二进制 因为 最高位是0)
可以看看这个表来总结:
例子:
20:(在18的前面32的后面 )
看16 看 16加多少等于 20 即使4 所以在4下面写上1其余补0
1024 512 256 128 64 32 16 8 4 2 1
1 0 1 0 0
所以20的二进制就是10010100
位运算
算术右移 >>
符号位不变,低位溢出删除,高位补零!
先算出10的2进制
0 0 0 0 1 0 1 0
0 0 0 0 1 0 1 0 符号位不变,低位溢出删除,高位补零!
==========================================
0 0 0 0 0 1 0 1 5
1*2的0次方=1
0*2的1次方=0
1*2的2次方=4 所以 他的结果是5
举个例子:5>>2 (解析:把五的二进制数右移两位)
先算出5 的二进制:
0 101 右移两位,符号位不变
0 00101 低位溢出删除,高位补零!
最后结果:0 001
转回十进制就是1
如果是负数就是先转码然后位移
算术左移 <<
符号位不变,高位溢出删除,低位补零!
举个例子:5<<2 (解析:把五的二进制数右移两位)
先算出5 的二进制:
0 101 左移两位,符号位不变
0 10100 高位溢出删除,低位补零!
最后结果:0 10100
转回十进制就是20
往左移得到的数字远远比本来的数字大
符号位不变,高位溢出删除,低位补零!
10 << 1(解析:把10的二进制数右移1位)
先算出10的2进制
0 0 0 0 1 0 1 0
0 0 0 0 1 0 1 0 符号位不变,高位溢出删除,低位补零!
==============================
0 0 0 1 0 1 0 0 20
0*2的1次方=0
1* 2的2次方=4
0*2的3次方=0
1*2的4次方=16
所以0+0+4+0+16=20
举个例子:5<<2 (解析:把五的二进制数右移两位)
先算出5 的二进制:
0 101 左移两位,符号位不变
0 10100 高位溢出删除,低位补零!
最后结果:0 10100
转回十进制就是20
如果是负数就是先转码然后位移
总结:
算术右移(往右移得到的数字远远比本来的数字小 )
算术左移(往左移得到的数字远远比本来的数字大 )
所以要想得到比本身转换二进制的那个数字大的话 就往左移
要想得到比本身转换二进制的那个数字小的话 就往右移
如果是负数就是先转码然后位移
逻辑右移 >>>
又叫无符号右移
不管符号位!低位溢出删除,高位补零!
所以呢,,逻辑右移的其值永远是正数,剩下的跟算术右移大同小异
无符号右移的规则只记住一点:忽略了符号位扩展,0补最高位 无符号右移运算符>>> 只是对32位和64位的值有意义
按位与 &
两位都为1,结果为1
取 5&3
5 二进制:101
3 二进制:011
101
& 011
001
结果为1
按位或 |
两位有一位为1,结果为1
取5|3
5 二进制:101
3 二进制:011
101
| 011
111
结果为:7
按位异或 ^
必须是一位是0,一位是1,结果才为1
取5^3
5 二进制:101
3 二进制:011
101
^ 011
110
结果是:6
按位取反 ~
取~3
3 二进制:0 011
整体取反 1 100
负数。。。补码转原码,原码转十进制
-1取反:011 100
符号位为1,所以最后值:-4
有个规律:就是数值+1之后取相反的值