什么是“二进制”及相关的几个有意思的问题

对于文科生而言,理解二进制是一件从骨子里觉得自己不可能理解的计算机知识点。

但其实这个知识点很有趣,我希望能够用尽可能简单的方式来解释清楚。


一、什么叫做“进”


我们经常讲的二进制、十进制、十六进制、六十进制......都有个“进”字儿。最好理解“进”的是我们平时使用的十进制:


0、1、2、3、4、5、6、7、8、9、停!


怎么着?怎么不继续数了?不应该是接着数10吗?


不。得分析一下。


我们按照十进制去数数的时候,一共就只有10个数儿,分别是0到9。(注意哈,0-9是十个数儿哈)


既然十进制是十个数儿,那9之后肯定要从这10个数儿里选,而且还不能选一个数儿,得选俩数儿,因为一个数儿都用完了。


如果选俩数儿,就得从最小的俩数开始选,这两个数就是:0和1。


但又不能是01,只能是10。


所以9后面就是10。


这就是“进”。


二、二进制


前面讲了十进制,十进制一共涉及到10个数字,那么二进制就是涉及到两个数字:0和1。


在二进制里面数数的时候还是从0开始数,第二个数儿是1:


0、1、停


那么1之后应该是什么呢?


按照前面讲的“进”的方式,1后面的数字肯定是两位(因为0和1都是一位),而且必须由0和1组成。


01肯定不行,因为01就是1,00也不行,00就是0。


所以只能是:10


0、1、10


10之后呢?肯定要把后面的0替换成1,所以是11。


0、1、10、11


那11之后呢?现在由0和1组成的两位都已经用完了,只能是跟一个三位数字,而这个三位数字又必须是由0和1组成。


000是3位,但000就是0。

001也是3位,但001就是1。

010也是3位,但010就是10.


可见,这个三位数字肯定得是1开头,不能是0开头,得是:


1**


那后面两位数是什么呢?


肯定是0和1组成的两位数,那我们就从00开始:


100


因此:


0、1、10、11、100、.......


按照这样的计算方法,我们就能自己把二进制的数儿一个个排出来了。


三、幂(指数)


虽然这个帖子的标题是讲二进制是什么,而我们已经解释清楚二进制是什么把数字表示出来的了,但为什么还要讲“幂”呢?


因为,要想进一步理解二进制的使用,还得讲一些幂是什么。


高中数学里幂和指数经常混为一谈。


我们可以这样理解二者的区别:


2的3次方(写作:2^3)


我们求2的2次方的过程就叫做:幂(Power)运算。


英文是这样解释的:


An expression that represents repeated multiplication of the same factor is called a power.


其中2是底(base),3是指数(exponent)


英语读作:2 to the power of three


汉语读作:2的3次方或者2的3次幂


好的,把上面这两个容易混淆的概念解释清楚后,我们来看十进制与这个概念有啥关系:


999


这是一个十进制的数字999,一共有三位:百位、十位和个位,对应的数字分别是:100、10和1


所以:999 = 9*100 + 9*10 + 9


我们用的是十进制,所以我们可以通过10为底的幂运算来分别获得100、10和1,即:


10^2 = 100 (10的2次方)


10^1 = 10 (10的1次方)


10^0 = 1(10的0次方)



那么我们接下来再看二进制:


10101


我们可以用同样的方法来表示,但区别是这回的底是2,而不是10:


1*2^4 + 0*2^3 + 1*2^2 + 0*2^1 + 1*2^0 =

16       +0         + 4       +0        +1        =


21


所以二进制10101对应的十进制就是21


通过这个例子我们可以轻松完成二进制到十进制的转换,不过这个还只是让大家更容易理解如何把幂运算与进制结合到一起。


我们接下来再看一个问题:


如果给你4个盒子,每个盒子里只能装1或者0,那么这4个盒子一共能有多少种排列的可能?


你可以手动计算:


0000

0001

0010

0011

.......


但是我们可以这样运算:


四个盒子如果都是1就是:1111


用以2为底的幂运算计算:


1*2^3 + 1*2^2 + 1*2^1 + 1*2^0 =

8       + 4       + 2       + 1       =


15


也就是说这四个盒子能存储的最大的十进制数字是15,而最小的十进制数字是0(对应的二进制是0000)


而0到15一共是16个数字,所以四个盒子一共能有16中排布方式,而16又恰好是2^4(2的4次方),15就是:2^4 -1 (即16-1)


这些排布方式对应的十进制范围就是:0 到 2^4 -1


那么换一个问题:


如果有32个盒子,那么这32个盒子能有多少种排列呢?


根据上面的计算,对应的十进制范围就是:0 到 2^32 -1 


即:0 到 4294967295


那我们现在再出一个新的问题:给你4个盒子,第一个盒子可以填正号(+)或者负号(-),后面的三个盒子则每个盒子可以填写0或者1,那么请问:这4个盒子一共有多少种排序,其中对应的正数有多少个,负数有多少个?


这个问题应该很简单吧?


假如第一个盒子是正号,那么剩下三个盒子的最大数就是:2^3 -1,如果第一个盒子是负号,那么剩下的三个盒子的最大数也是:2^3 -1


同理,如果是32个盒子呢?


如果是32个盒子,那么第一个盒子是正号,剩下的31个盒子的最大数就是:2^31 -1;如果第一个盒子是负号,那么剩下的31个盒子的最大数依然是:2^31 - 1


因此这32个盒子能够显示的最小的负数就是: -(2^31 -1),能够显示的最大的正数就是:2^31 -1


好了,现在,我们再给大家换一种描述的方法,把“盒子”改成:“位”(bit)


如果计算机上的一个存储空间有32位(32 bits),那么请问,这个存储空间能够存储的最大的整数是什么?


如果这个存储空间的第一位必须是正号或者负号,那么这个存储空间能够存储的最大的整数又是什么?


希望大家已经可以自己计算出来了。


四、UTF-8和UTF-16


有了上面的知识,我们知道其实“位”(bit)就是个盒子,因为盒子就是用来存储东西的空间嘛。计算机里也是有存储空间的,计算机里的存储空间也是盒子,这些盒子只能存储0和1,而不能存储英文字母和汉字。


为了能够存储英文字母和汉字,就只能让所有的英文字母和汉字都有对应的0和1,即二进制。


那我们就这样来安排,用三位吧(3 bits)


000  -> a

001  -> b

010  -> c

......

111 -> g


完了,3位只能表示到g,可我还有那么多个英文字母呢,而且我还有那么多个标点符号呢?


由于早期的计算机是美国人做的,所以他们只想用来表示英文字母和标点符号,然后他们发现7位就可以了:


(二进制)1111111 =(十进制)127


7个盒子能够表示的最大数是127,最小的数是0,所以7位可以用来表示128个符号。


但是计算机里一个字节(Byte)等于8位(bit),得凑个整呀?


于是就规定了第一位是0,其他的位可以是0,也可以是1。


这就有了最早的文字编码方式:ASCII(美国信息交换标准代码)


可这种编码方式只能表示英文字母和标点符号,汉字和其他语言都表示不了,所以ASCII只能美国人自己玩儿,其他国家的人还得搞出新的编码方式,像汉字这种7位肯定不够,得多加一点儿。


于是汉字的编码就搞了2个字节(2 Bytes),因为1个字节是8位,所以2个字节就是16位。


好家伙,你自己算算16个盒子能有多少个排列? 给你个参考:2的16次方 = 265536 


完全够了!


于是,汉字就采取了双字节的方式来编码。


这人啊一旦有了钱,就会为所欲为。16个盒子怎么能够?我要32个盒子、64个盒子!


于是就有人想,能不能用尽可能多的位数来表示编码文字呢?这样人类有多少儿符号都能给它编码。


然而,并不是位数越多越好,因为土豪有的时候过于浪费,如果你用32位,也就是4个8位,加入表示第一个英文字母a,就得是这样:


00000000 00000000 00000000 00000000


这么多个0,你受得了吗?


你要是受得了,计算机还受不了呢。


于是,人们就想怎么才能节约一些空间,少用一些0。


所以有些符号(比如英文),就用8位来表示吧,有些符号就用16位来表示吧。


这里面还有很多知识,我这里就不多介绍了。


总之,UTF-8的8是8位的意思,UTF-16的16是16位的意思。


现在你写的网页、代码,大部分的符号都涵盖到了UTF-8这种编码方式里,所以你把文件的文字编码方式选为UTF-8就大概率不会出现乱码了。


之所以出现乱码,就是因为你想显示的文字并没有对应的二进制编码。


已邀请:

要回复问题请先登录注册