一起来看看神奇的二进制吧!

8 hjs 11小时前 64次点击

大家好,时隔多日发篇技术贴。

今天我想讨论的是构成现代计算机的地基,二进制!

有关二进制的基础概念,在这里我就不做赘述了,感兴趣的可以百度。

我想讨论讨论二进制更深层的含义。

二进制总的来说有两种作用,第一是编码,第二是计算。

我觉着编码就是对我们熟悉的各类事物进行一个抽象。也可以这么讲,编码就相当于把我们熟悉的事物换成了另外一种表现形式。

二进制只有0和1,每个0或者1代表二进制的一位。所以可以这样认为,一位二进制只能编码两种信息。很典型的例子,硬币的正反面就可以用二进制的一位进行编码。0可以代表正面,1可以代表反面。

计算机内部所有的数据(注意哈,是所有),都是这样进行编码的。但单靠一个二进制不可能编码海量的数据,所以衍生出多位二进制和情景编码。

二进制的编码组合,是随着二进制位数的增长呈指数级增长的。比如,一位二进制有两种编码方式。两位二进制就有4种编码方式,三位二进制就有8种编码方式。所以我们可以推算出一个公式: 如果二进制的位数为m,那它具有2的m次方那么多的编码方式。

除此之外,便是根据情景不同,同一种编码可以解释为不同的东西。比如说: 某种字符的编码与某个音频格式的编码是一样的,但由于解析的情景不同,它们便指向了不同的东西。

计算其实也是一种编码,二进制它本身就代表数字。 计算机内部所有的计算都是对二进制执行的。

下面说一下这篇帖子的核心,原码,反码和补码。

跟大家说一下,计算机的内部有一个算术单元(ALU)。这玩意儿是专门负责计算的。它的核心部件是一个叫加法器的东西,但很不幸,这里并没有减法器。

那减法怎么实现呢?在数学上减去一个数等于加上这个数的相反数,所以它的减法就是使用加法实现的。

比如5 -2 = 5 + -2 = 3。大家觉得这有问题吗?没问题啊,肯定是没问题的,对吧。

但是在计算机里,这会出现一个巨大的坑。

还是拿上面的例子说明,5的二进制是101,2的是10。如果我们直接做加法,101 + 10 = 111。转回十进制,结果是7。这肯定不是我们想要的。

这个时候你们可能就说了,我刚才说的是2的十进制,它也不是-2啊。所以,要想真的加负2,我们必须与正2区分开。那我们再把思维跃迁一下,-2是不是带一个符号啊,管他叫有符号数没毛病吧。在数学定义中,是不是正数可以忽略前面的加号啊,那管他叫无符号数是不是没毛病啊。

我们总结一下,所以要想实现减法,是不是可以用一个无符号数加上有符号数啊。所以我们必须得有符号数进行编码与无符号数区分开。

其实他们的编码并不难,只不过引入了一个符号位。符号位位于二进制数的最高位(从左往右数第1位),比如十进制的1000000,最高位是1。如果符号位为0,代表这串二进制为无符号数。如果符号位为1,代表这是一串有符号数。

迅速做几个练习来快速的适应这种变化: 0101 = +5,0111 = +7。1111 = -7,1001 = -1。为了区分正负数,我用正号和负号给他们明确标注了一下。

现在大家高兴了,有了这个区分之后,那肯定做加法就嘎嘎顺利了,对吧?

那我们试一下呗,如下: 0100 + 1010 = 1110,上面的算式是 4 + -2 = -6。这个结果我想一个刚上初一的学生过来看了都直摇头啊。所以这肯定是不对的。但我们的工作也并没有白费,我们只需要换一个思路。

接下来我会用4位二进制范围(0000 / 1111)来举例子。先明确四位二进制,一共能表示多少个数字。2的4次方16,所以一共可以表示16个数。然后16÷2=8,所以负数拥有8个数字,正数也拥有8个数字。所以四位二进制数能表示的数字范围是-8 到 7。0000 为 0,被划分到正数区间(必须这么做)。所以负数和正数的上限会差一。

有学编程的小伙伴吧,听没听过有符号byte的范围是 -128 到 +127,这个差一就是这么来的。

接下来的内容非常抽象,我尽量讲清楚。

假设有一个圆盘,上面有若干的格子,每个格子上标示着一串二进制。我们用这个图形代入我们的这四位二进制,那整个圆盘顺时针从0000开始,到1111结束。

如图所示:

二进制补码演示图 图片

这个图片是这样的,最上面是0000(10进制数字0),然后向右转圈,会经过0001,0010等。一直转完一圈,停在1111(形成完美的圆环)。这里前面带0的全都是无符号数,图片中0111后1开头的是有符号数。

因此1000是-8,不要认为是-0哈,这是错误的,没有-0这个东西。那我们继续往后推,1001是 -7,1010是 -6,1011是 -5,此处省略,直到1111 是 -1。

是不是感觉有哪里不对劲?为什么这里的复数的编码变了,和我们上面讨论的那个不一样。还记得4-2的这个例子吗?

在这个例子中-2是1010,但在这张图中,它显示的是1110。如果有已经看懂的同学更会惊讶地发现这张图中的复数部分的编码正好和正数反过来了。

这就是我说的转换的思路!

我来举个比较形象的例子,某某学校举办了一场公平的跑步比赛。但这个学校高个子有6米那么高,矮个子却只有两米那么高。为了让高个子和矮个子都有公平的机会到达终点,学校规定,矮个子可以站到离终点近的地方,高个子要站到远的地方。

这张图复数部分跟这个学校的规则一样。小数放在离正数近的地方,越大的数离正数越远。

我已经强调过,这张图片是一个圆盘。在圆盘上做加法代表顺时针移动,而且无论移动多远都不会跑出圆盘(因为这是一个环结构)。

说了这么多,这种转换的思路和这个圆盘到底有什么关系?我们依然拿4-2的例子,但这次我们用圆盘上的数字来做计算。在圆盘上,四依然是0100,但-2是1110。0100 + 1110 = 10010。这个结果是个5位的二进制数,这里很明显是溢出了。

我们不用管它,直接把最高位的二进制位省略,得到0010。我们发现这一次得到的结果,对应的10进制数正好是2。采用这种方式,便完美地解决了所有问题。

可以静下心来思考0100,1110,0010它们三个的关系是什么呢?

关键是距离,4到2如果顺时针走的话,距离为多少呢?

我们可以在脑海中数一下,答案其实是14。14对应的二进制就是1110,在这个圆环内,4+14正好绕回环内的2。所以知道为什么-2的二进制在这里要被标成1110了吗?就是因为距离,圆盘内,从任意一数出发,经过14个点,终点肯定是这个数减2的结果(不信你就试试)。

4-2=2, 如果我们逆时针走的话,只需要走两格,这肯定是很近的。但我说了,加法只能顺时针走,所以要跨越整个圆盘才能走到2。所以才需要把-2放在1110的位置,-1的1111也是同样的道理。4-1=三,逆时针讲,它离四更近,但顺时针离四更远。所以需要把一放在1111,也就是第16个格子上。

如果有个圆盘m,它的格子数量为k。负数n在圆盘上的位置为,k - n(n 不等于0 且 n 小于等于 k ÷ 2)。

其实到现在,大家应该很明白这些有符号数,其实占用的是无符号数的二进制。只不过通过环的特性,恰好的解决了减法出现的各种问题。

图片中负数的二进制,有个专有名词叫做补码。接下来我来说一下如何算出任意一个负数的补码。

首先算出这个负数的绝对值的二进制(这个结果叫源码),然后对得到的源码的每一位进行求反(0变1,1变0),这个阶段得到的二进制结果叫做反码。然后在反码的末尾加上1,最后得到了补码。

其实本质上这个计算就是要算出有符号数应该映射在哪个无符号数的二进制上。

所有的无符号数都是源码。

最后贴一段练习吧: -6 的补码怎么算。首先拿到+6的二进制(源码) = 0110(算上了符号位)。娶返拿到反码 = 1001。最后末尾加上1 = 1010。

来验证一下1010是不是-6的补码,直接带入我们的万能工具小圆盘。为了简单起见,我们用4位二进制数来验证。16-6=10,10的源码就是1010。当然如果不放心的话,还可以继续来算一下。

看看6-6等不等于0,0110 + 1010 = 10000,丢弃最高位一出位,符号为指向正数,全0代表0。所以运算正确,-6的补码是1010。

上文中提到的负数军代表有符号数,正数代表无符号数。我有的时候会把它们混用。

好了,到这就算是差不多写完了。感谢点进来的朋友们,这篇帖子我花了好长时间来组织语言。尤其是圆盘那一部分,我不知道怎么描述才能让没有经验的人也能参与进来。所以有很多别扭的地方。但我已经尽可能的把我表达的东西表达出来。

如果这篇帖子能帮到正在学习计算机组成原理的同友们,我更开心。希望每个热爱技术的人都有所收获,有所深入,而不是浮于表面,只观其轮廓。

共 2 条评论
顶帖,这个帖子加不了精华可惜了
hjs [楼主] 11小时前
0 

笔者能力有限,错误之处在所难免。欢迎指正批评,一起交流。