1,导语
追根究底的习惯是深度分析和解决问题,提升程序员素质的关键所在,有助于编写高质量的代码。
基础知识的深度认识决定着知识上层建筑的延展性。
2,前言
1,我们为什么要了解二进制?因为计算机对信息的存储及计算都依靠二进制。
2,我们看到的图形渲染,网络远程共享,大数据计算,这些其实都是计算机在对0与1进行信号处理。
3,很多优秀的应用算法都用到了位运算,而位运算则是以二进制为基础建立起来的。
3,十进制是什么
在了解二进制之前,我们先来了解十进制。十进制又是什么呢?我可以说你从出生到高中毕业期间,遇到的数学数字基本都是十进制数,比如:1,23,456,712等。而我们常用的算法也是十进制算法,因为它很好理解。1+1=2,3+4=7等。
4,二进制是什么
为什么?
1,讲完十进制,可能你会问,那我们为什么还要用二进制呢?因为我们用的计算机是用二进制来运算。
2,其次,你可理解十根手指和二根手指,哪个运算更方便呢?当然是二根手指。
3,二根手指怎么运算?这就用到了二进制了。
是什么?
想了解为什么?我们通常会先问度娘。【百度百科】
我们可以看到上面说“二进制(binary)是在数学和数字电路中指以2为基数的记数系统,以2为基数代表系统是二进位制的。”,这是百度上的定义,我们接着看。
5,区别及转换
那十进制和二进制它们有什么区别呢?它们之间怎么转换呢?
区别:
1,十进制常用于生活中的数学运算等,而二进制是计算机上的运算方式。
2,十进制数在计算机上运算得出的结果,其实也是计算机把十进制数先转换成二进制数,再运算,再转换成十进制数得出的。
转换:
先举例[左边是十进制数,右边是二进制数]:
1=1,10=2,100=4,1000=8,11000=24,即12^0=1;12^1=2;12^2=4;12^3=8;12^4+12^3=24。
我们可以看到十进制数转二进制数,从右往左可以看成从低位到高位,具体转换:先从左往右,以每位数字为基本,再乘以2[转二进制数],其指数是当前位数-1[比如:12,1是10位,后面还有一位,转换二进制数,是12^1+22^0=4]。
十进制数转二进制数[正数]
二进制数转十进制数[正数]
**
6,计算机怎么运用二进制处理信息【规则】重要
6.1,物理表现【电路】
二进制具体的物理表现
二极管的断电与通电;
CPU的低电平与高电平;
磁盘的电荷左右方向。
。。。等
扩展
设想有8条电路,每条电路有低电平和高电平俩种状态。根据数学排列组合,有8个2相乘,即2^8,能够表示256种不同的信号。假设表示区间为0~255,最大数即为2^8-1,那么32条电路能够表示的最大数为(2^32-1)=42 9496 7295。平时所说的32位机器,就能够同时处理字长为32位的电路信号,以及64位,同理。
6.2,二进制的三种表示数
在二进制的世界里,表示数的基本编码方式有三种:原码,反码,补码;
分类 | 正数 | 符号位 | 负数 | 符号位 | 表示范围[8位二进制] |
---|---|---|---|---|---|
原码 | 符号位和数字本身,即数值本身 | 0 | 数值本身 | 1 | [-127,127] |
反码 | 数值本身 | 0 | 正数表示基础上各个位取反 | 1 | [-127,127] |
补码 | 数值本身 | 0 | 正数表示基础上各个位取反后加一 | 1 | [-128,127] |
三种编码方式的对比
**
正数/负数 | 原码 | 反码 | 补码 |
---|---|---|---|
1 | 0000 0001 | 0000 0001 | 0000 0001 |
-1 | 1000 0001 | 1111 1110【各个位取反】 | 1111 1111【取反后加1】 |
2 | 0000 0010 | 0000 0010 | 0000 0010 |
-2 | 1000 0010 | 1111 1101 | 1111 1110【逢二进一】 |
声明:下面的示例都是8位二进制数,空位补0;
6.3,表示数的演进
演进
原码—》反码—》补码
具体
开始,原码的编码方式已经符合人类的认知了,但为什么还会有反码和补码的出现呢?
因为计算机的运作方式和人类的思维模式是不同的。为了加速计算机对加减乘除的运算速度,减少额外的识别成本,反码和补码应运而生。
反码的诞生:
以减法计算为例,减去一个数等于加上这个数的负数,例如1-2=1+(-2)=-1。而用原码计算的话,1-2=1+(-2)= [0000 0001]原+[1000 0010]原=[1000 0011]原=-3,结果显然不对。
但使用反码计算,1-2=1+(-2)=[0000 0001]反+[1111 1101]反=-1,结果正确。
补码的诞生:
某些特殊情况下,使用反码计算,会产生认知方面的问题,例如2-2=2+(-2)=[0000 0010]反+[1111 1101]反=[1111 1111]反=-0,结果出现了-0,但实际上0是不存在+0与-0的表达方式的。
解释一下:[1111 1111]反=-0,首先,最左侧的1是表负数-,其次8位二进制数的表示范围是[-127,127], 2^7+2^6+2^5+…+2^0=255,已经超出范围。
随着数字编码表示的发展,补码诞生了,解决了反码中+0和-0的问题,例如:2-2=2+(-2)=[0000 0010]补+[1111 1110]补=[0000 0000]补=0。
还有一个好处,即在占用相同位数的条件下,补码的表达区间比前俩种编码的表达区间更大。例如,8位二进制编码中,补码表示的范围增大到-128,其对应的补码为[1000 0000]。8条电路的最大值为0111 1111即127,所以补码的范围为[-128,127]。
6.4,常用运算
重要点
【记住】二进制整数最终都是以“补码”形式出现,意思是使用补码来计算。
原因:正数的补码与原码,反码一致,负数的补码则是反码加1而定结果。这样使减法运算可以使用加法器实现,符号位也参与运算。
运算举例
负数 补码 运算举例(从右往左算):
35+(-35)=0
0010 0011【35】
1101 1101【-35】
———————————
0000 0000【逢二进一】
35+(-37)=0
0010 0011【35】
1101 1011【-37】
———————————
1111 1110【逢二进一,借一当二】
这里使用的是补码运算器,减少了中间变量存储的开销,也降低了CPU内部的设计复杂度,使内部结构更加精简,计算更加高效,无论对于指令,寄存器,还是运算器都会减轻很大的负担。
图片示例
二进制加减法
其他
二进制计算结果溢出
-35-128=(-35)+(-128)
1101 1101【-35】
1000 0000【-128】
———————————
10101 1101
当结果需要9条电路来表示时,即结果溢出,一旦溢出,计算结果就会出错。
所以,在各种编程语言中,均规定了不同数字类型的表示范围,有相应的最大值和最小值。
7,位运算
7.0,有趣点
1,既陌生又熟悉
陌生:不易理解且不常用
熟悉:“别人家的工程师”在代码中经常使用这种方式进行 行高低位 的截取,哈希计算,甚至运用在乘除法运算上。
2,在具体位移运算时,向右移动1位近似表示除以2,十进制转二进制后,在向右移时,最右边的1将直接抹去,说明向右移对于奇数来说,并非完全相当于除以2。
7.1,基本了解
对二进制数值进行位数位移,称为位运算;
在左移<<与右移>>俩种运算中,符号位均参与了移动,
除负数往右移动,高位补1之外,其他情况均补0在空位处。【*】
7.2,左移运算
左移运算由于符号位参与了向左移动,在移动后的结果中,最左边可能是1或0,无论十进制数是正数或负数。
7.3,带符号位移运算
注意点:在左移<< 与 右移<< 俩种运算中,符号位均参与移动;除负数往右移动时,高位补1之外,其他情况下空位均补0。
带符号位移运算
**
正数/负数 | 向左移<<1位 | 向右移>>1位 |
---|---|---|
正数(35的补码 0010 0011) | 0100 0110=26+22+21=70 | 0001 0001=24+20=17(近似除2) |
负数(-35的补码 1101 1101) | 1101 1101=1(1000101+1)=-70 | 1110 1110=1(0010001+1)=-18 |
正数(99的补码 0110 0011) | 1100 0110=-58(正数变负数) | 0011 0001=49 |
负数(-99的补码 1001 1101) | 0011 1010=58(负数变正数) | 1100 1110=-50 |
【-35向左移动1位=-70 】
7.4,无符号位移运算
对于三个大于号的>>>无符号向右移动(注意:不存在<<<无符号向左移动的运算方式),即直接无视符号位,高位直接补0,根本不关心正数,负数问题。此运算常用于高位转低位的场景中。
无符号位移运算
**
正数/负数 | 向右移>>>1位 | 向右移>>>2位 | 向右移>>>3位 |
---|---|---|---|
正数(35的补码 0010 0011) | 0001 0001=17 | 0000 1000=8 | 0000 0100=4 |
负数(-35的补码 1101 1101) | 0110 1110=110 | 0011 0111=55 | 0001 1011=27 |
7.5,其他操作
位运算的其他操作
应用
1,按位与(&)运算典型的场景是获取网段值,IP地址与掩码255.255.255.0 进行按位与运算得到高24位,即为当前IP的网段。
2,按位运算左右俩边都是整型数,true&false这样的方式也是合法的,因为boolean的底层是0与1。
3,短路问题
3.1,按位与与逻辑与(符号为&&)运算都可以作用于条件表达式,但后者具有短路功能。
boolean a = (1==2) && (1==1);
因为1==2为false,所以触发短路,直接退出,不会去验证1==1的正确性,反之按位与&,则执行的结果是1==2和1==1是false与true,但最终结果都是一样的。
3.2,按位或与逻辑或(符号为||)同上。
boolean b = (1==1) || (1==2);
因为1==1为true,逻辑或是只需要有一个条件为true即可,执行1==1为true,触发短路,直接走下一步,如果把 || 改成 |,效果是一样的。
3.3,异或运算没有短路功能,通常在哈希算法中用于离散哈希值,对应的位上不一样是1,一样是0。
例如:1^1=0,0^0=0,1^0=1,true^true=false,true^false=true。
8,计算机的存储计量单位
一条电路线在计算机中被称为1位,即1个bit,简写为b。
8个bit组成一个单位,称为一个字节,即1个Byte,简写为B。
1024个Byte,简写为KB;1024个KB,简写为MB;1024个MB,简写为GB。
宁静致远,天道酬勤。
书上得来终觉浅,绝知此事要躬行。