0 前言
本文以十进制整数为例,使用2个最简单的表达式char a = -20;
和char c = a + b;
,为你深入浅出地讲解计算机思维,力求将抽象的计算机思维具象化讲解,同时,我将为你描述一个宏大的计算机世界的蓝图。
计算机思维与核心思想概要:
- 人类世界与计算机世界的通道:编码与译码
- 计算机处理信息的本质:二进制信息的运算
- 现实世界向计算机世界的映射:二进制信息运算的原则
- 人类与计算机斗争的胜利与妥协:分而治之、抽象思想与分析程序行为、分工协作
为了避免内容的冗杂,本文只谈及十进制整数和二进制数,力求使用最浅显易懂的知识,讲清楚高深的计算机思维。
1 人类世界与计算机世界的通道:编码与译码
本小节,从最简单的十进制整数与二进制数的相互转化,来解释编码与译码。
1.1 一段简单的C语言代码
你需要使用VS 2017进行单步调试和查看内存。
补充链接:使用VS 2017进行单步调试和查看内存
这里我们用char
代表能够存储一字节大小的机器数的容器,并不使用其字符的功能。
你可以想象,这是一个char类型的容器,能够存储8位二进制数。
以下是我们即将展开讲解的C语言代码:
#include <stdio.h>
#include <Windows.h>int main() {char a = -20;unsigned char b = -20;system("pause");return 0;
}
1.2 查看变量的内存情况
首先,我们查看一下数据a
和b
在内存中的情况,这个时候,计算机已经完成了十进制整数到二进制的转换,内存中存储的是对应的二进制信息,通常采用十六进制表示。
变量a在内存的情况:
变量b在内存的情况:
如果你不知道如何查看变量地址的话,可以通过C语言中的&a
和&b
,输出到控制台来查看。
我们可以看见,不管是带符号的变量a还是不带符号的变量b,将-20
赋值给它们,存储到内存中的,都是十六进制的ec
,也就是二进制的11101100
。
这里表明,计算机是先将-20
转换为11101100
,然后再放入变量中的。
我们查看一下【局部变量】:
这里表明:
- a和b的二进制信息是完全一样的
- 他们输出到屏幕的数据类型和十进制数值不一样的
这是为什么呢?
1.3 计算机编码:从十进制到二进制
我们再看下面的图
首先,我来解释一下从通过键盘输入到存储存储器的过程
- 从屏幕键入
-20
,计算机先进行编码,变成了二进制的11101100
- 再将二进制信息,存储了变量a和b中。其中,变量a和b分别是带符号和不带符号的
char
类型数据
这里有两个不同颜色的盒子
- 它们分别代表
char
类型和unsigned char
类型 - 他们分别被打上了标签
a
和b
- 他们都存入了二进制信息
11101100
1.4 计算机译码:从二进制到十进制
下面我来讲解一下,从二进制信息到输出十进制的过程。
尽管a和b两个盒子中的二进制信息完全一样,但是你要清楚,这只是在计算机世界完全一样,在人类世界中,二进制信息的含义应该是:二进制信息的含义 = 位 + 上下文,所谓上下文,就是二进制信息所处的环境。
参考学习:《深入理解计算机系统》的1.1节
也就是说【11101100
+ 数据类型】,通过这两个条件,才能正确得到现实世界中,二进制信息的含义,这里我们将二进制,以十进制形式进行输出。
- 对于变量a,以带符号的十进制形式输出,因为它被转换为二进制之前,就是带符号的十进制数。
- 对于变量b,以无符号的十进制形式输出,
-20
以补码形式转换成二进制数,然后再存入b中,此时这个二进制数的含义发生了改变,因为它的上下文从带符号数变成了无符号数。
这里我们需要强调的是,对于十进制与二进制的相互转换,大多情况下,是怎么进去的,就要怎么回来,除非特殊需求,比如需要将十进制数转换为字符输出,这也是允许的。
1.5 小结
本节我为你展示了两个过程
- 十进制 --> 二进制,这个过程叫编码
- 二进制 --> 十进制,这个过程叫译码
计算机的外部设备,鼠标、键盘、音响和显示器等等,这些都是从人类世界进入计算机世界的入口。
人类通过这些外部设备输入信息(十进制数、文字、图片、视频、音频……),由计算机进行编码,以二进制数的形式进入计算机世界,你也可以理解为入乡随俗。
这些二进制数在计算机的世界里遨游,有些二进制数是数据,有些是指令,这些指令是计算机世界的指挥者,他们指挥着数据工作,这些数据可能进行加法工作,可能进行乘法工作……
当这些二进制数,完成了他们的探索使命,就要回到人类世界,这个时候,他们将会通过计算机进行译码,恢复他们在人类世界的本来面貌。
你可以想象,一架宇宙飞船,从人类世界,通过虫洞进入计算机世界,在完成任务后,又通过虫洞返回人类世界。
2 计算机处理信息的本质:二进制信息的运算
2.1 体验计算机的二进制运算
我们把上一小节的代码,再加上一行代码char c = a + b;
char a = -20;
unsigned char b = -20;
char c = a + b;
我们查看一下内存和局部变量:
可以得知,变量c
对应的十六进制是d8
,二进制是11011000
,又因为它是char类型,因此二进制信息对应的十进制信息是 -40。
这里你是不是有疑问?试想,如果是按照十进制进行相加-20 + 236
,肯定不等于-40
,并且,一个char类型的数和一个unsigned char类型的数据,不同的数据类型相加,又是怎么进行的呢?
这里,也就可以谈及我们的要点,信息处理的本质,是二进制信息的运算。我们所有的信息,都是先转换成二进制信息,再进行相关运算,运算结束后再根据其上下文,返回对应的结果。
我们根据这个过程,再来审视一下刚才的例子:
- 将
a
和b
的内部是二进制信息,将它们进行加法运算,得到结果 - 将结果放进容器
c
中 c
中的二进制信息,再由计算机译码,转换为十进制输出到屏幕
如果我们将最后一条加法改成unsigned char c = a + b;
,c的结果将会是216
,具体过程留给读者思考。
需要注意的是,这里我举这个例子,只是为了说明本文的观点,事实上,C语言编程中,非常不建议将无符号与有符号数混合运算,因为那样得到的结果很可能令人费解,可能也没有什么现实含义。
2.2 小结
本小节为你讲述了这些内容:
- 对于
char a = -20;
,计算机先将-20以补码的方式转换为二进制信息11101100
,在将其放入变量a所对应的内存中。 - 对于
char c = a + b;
,计算机会在CPU中,会进行如下过程- 将a和b的二进制信息进行加法运算
- 将得到的结果放进变量c所对应的内存中
- 再转换为十进制显示到屏幕上
在计算机的世界里,只有二进制数,这些二进制数,在计算机世界中,按照人类设定的规则不断地运算,完成任务后,又以原本的身份回到人类世界。
这,就是计算机处理数据的本质,计算机按照人类设定的规则进行二进制运算。
推荐阅读《编码:隐匿在计算机软硬件背后的语言》
3 人类世界向计算机世界的映射:二进制信息运算的原则
计算机是人类发明的工具,是人类智能的延伸,因此,计算机世界的运算法则,要遵从人类世界的运算法则,才能更好地为人类服务。
例如人类世界中,1+2 = 3
,那么在计算机世界中,0001 + 0010
也要等于0011
。
无论是加减乘除法,还是其他种种,都有遵循这个原则,这样人类才能更方便地利用计算机解决现实问题。
因此,二进制数本质上就是现实世界在计算机世界的映射,它具备现实世界的含义。他们之间实现映射的通道是编码与译码。
我给出你一个表格,做个对比,让你清晰地感受这种映射。
人类世界 | 计算机世界 |
---|---|
领导者 | 控制器 |
基层员工 | 运算器 |
能源物质 | 数据 |
给你解释一下:
- 控制器在CPU内,能够指挥计算机怎样工作
- 运算器在CPU内,能够进行数据的运算
- 数据在计算机存储器(内存、硬盘等)中四处游走
给你推荐一个动画,能够让你清晰感受到:人类是高维生物,而计算机世界是人类创造的一个新的世界,这个世界是人类世界的映射,它为人类世界工作和服务。
推荐动画:《瑞克和莫蒂》第二季第六集:电池微世界
4 人类与计算机斗争的胜利与妥协
自从计算机被发明以来,人类与计算机一直在进行着永无休止的斗争,不断进行着碰撞与融合。
计算机是人造的产物,它是人类思维的产物,但是随着它的不断发展,其复杂性成指数级上升,独立的个体已经很难去控制它,因此,为了充分利用计算机来为人类造福,人类又发明了很多方法去控制它,去约束它。
计算机诞生以来,形成了很多的分支领域,也诞生了很多优秀的理论,这些都让人类能够更好地控制计算机,为人类造福,例如软件工程中的瀑布模型及其衍生模型、敏捷开发方法;又例如当今时代的火热技术人工智能、大数据;又例如面向未来的量子计算机……
人类在这场没有硝烟的战争中,有胜利,也有妥协。
4.1 人类的胜利
人类在这场战争中,充分发挥自身的智能,成功地使用分而治之的哲学思想和逻辑抽象的数学思想,战胜了复杂的计算机!
4.1.1 分而治之思想的应用
根据本文的核心理念,这里我只使用文章开始提及的简单表达式,来为你讲解分而治之思想的实际应用,然后给到你该思想的本质内核。
对于表达式char a = 3;
,我们可以将其分开看待:
- 3转换为二进制,看作
0011
- char看作某种类型的容器
- a看作容器的标签
这样,你就可以将这个表达式看成:将0011
放进贴着标签a的char类型的容器中。
这个简单问题,可能没有让你感受到复杂问题的简化,你可以想象一个需要你解决的问题:让你开发一款操作系统,这个问题足够复杂,但是其开发过程的各个环节,都渗透着分而治之的思想,我想你应该清楚它的重要性了。
该思想能够让复杂性问题简单化,让很难被解决的问题得以解决,事实上,人类面对大规模问题,都会采取这样的思想:软件工程的分工协作、硬件编程的层次建模……它有大量的应用场景,这个思想对读者来说,是年金,它每年都会给读者分红,时间越久,利息越多。
4.1.2 分而治之思想的本质
Divide et impera ——拉丁语,意为“分而治之”,引自Machiavelli的一句政治箴言,1532
分而治之的思想本质,就是拆解与转化:
- 将大问题拆解为小问题
- 将小问题拆解为更小的问题
- 将更小地问题转化已知的被解决过了的问题
Critical thinking(批判性思维)的相关资料指出:所谓创造,就是将已知的产物以全新的方式结合起来。
而分而治之的思想,正是通过问题拆解,转为已知,再综合结果的方式,实现了创造。
如果蛋糕太大一口吃不下,那就先切开它!然后一快一快吃下它!
期待你遇到大规模问题不要惊慌失措,你可以先拆解他、再转化它、最后综合起来,几乎任何问题都可以被解决。
4.1.3 抽象与实现
逻辑抽象是人类智能的体现,它是计算机所不具备的,面对一个复杂的问题,我们可以对其进行不同层次的抽象、建模,这些行为的进行,可以在人的脑子中,也可以在纸面上,或者在其他工具上。
根据抽象得到的结果,人类再使用计算机这个得力助手去实现它,这样就能真正地解决现实问题。
计算机领域的抽象与实现,可以是 [数据结构] 的抽象数据类型;可以是 [Verilog HDL] 的层次建模思想;可以是软件工程的UML建模……
抽象与实现的思想,其实渗透到了人类生活的各个领域,期待你能够以这样的方式去重新审视这个世界。
4.2 人类的妥协
人类不会向计算机屈服,但是面对一些挑战,也不得不做出适当的妥协让步,这也是为了更好的应用计算机高效率地解决现实问题。
4.2.1 分析计算机行为快速搞定bug
当程序没有按照你预期的结果执行,不要懊恼,不要悲伤,更不要想着:“为什么它没有按照我想的去做?”
这样的想法,只会让你更加懊恼和沮丧,你应该想的是:是不是我哪里没有描述清楚,所以它没有做好事情?
你应该做的是:按照程序执行的行为,使用单步调试/断点调试,逐一分析,直到找到问题根源。
计算机是个听话的孩子,它只会按照你告诉它的去执行,因此,如果它出错了,一定是你指挥失误,你只需要分析它的每一步行为,就能够以最快的速度找到错误,解决bug。
这是计算机历史上,导致计算机崩溃的一只虫子(bug),让我们一起,按照程序的行为,找到它,消灭它!
4.2.2 大规模项目的分工协作
随着计算机的不断发展,大规模复杂问题开始出现,独立的个体可以写出一个小程序,但是面对大规模问题,人类就如同《焦油坑》里的动物一样,不断挣扎,但是越挣扎,反而越痛苦。
直到软件工程出现,人类开始学会分工协作,共同应对棘手的“焦油坑”,成立了“外科手术队伍”,具备了解决大规模问题的能力。
推荐阅读:《人月神话》
你将会更加直观地感受到人类与计算机的斗争,比如焦油坑、外科手术队伍……
5 期待你更好地在计算机世界遨游
本文从一个最简单的表达式出发,为你描述了人类世界与计算机世界的宏大蓝图;给你讲述了重要的计算机思维,并将其具象化表达;给你讲解了重要的破解复杂问题的方法和适当妥协让步的策略。
计算机是人类智慧的延伸,是人类得力的工具,是人类的 “外包大脑”,永远记住,你不是程序员,不要当程序员,你是解决问题的人,你要利用人类特有的智能,这,才是你与计算机的不同,你能做到计算机做不到的事情,你要充分利用计算机这个得力工具去解决问题,不要被其反噬控制。
期待此文,能够为你带来全新的计算机世界观,让你更好地开启计算机旅程。
声明:
- 本文大部分图片均为自己制作,一些图片是我购买的具备个人版权的图片,还有极少数素材来源于网络,侵删。
- 本文中,部分的类比和比喻,伴有科幻主义色彩,非技术部分的内容可能并非严谨的科学事实,请勿恶意揣测,谢谢。
- 本文涉及的技术,为了方便你理解,采用了简化模型,并未展现完整的技术细节,技术细节你可以从我推荐的书籍中学到。