查看原文
其他

从1加到100:一道简单的数学题挑战下你的大脑

2017-01-03 刘欣 码农翻身

2017年的第一篇, 写给刚刚踏入计算机编程领域的小白吧。


所谓编程,就是把自然语言的需求翻译成计算机语言, 让计算机去执行。 对于刚入行的人, 理解CPU和内存是怎么在一起工作的, 绝对是基础中的基础。


1

CPU和内存


如果我们简化一下, CPU和内存其实特别简单,内存就是一个个的小格子, 每个格子都有一个编号, 格子中的数据可以被CPU所读写。

CPU 内部的构造超级复杂, 但我们这次只关注两个东西:


一是运算器,可以做各种运算, 但是有个限制,这个运算器不能直接操作内存进行运算, 他在运算时使用的是内部的数据格子(学名叫寄存器), 为了区分开, 我把他们叫做R1,R2,R3,R4,假设只有这么4个, 统称Rx。 


CPU必须把数据装载到寄存器中才能运算。


CPU运行速度快的令人发指, 但是它能做的事情却简单的令人发指, 主要是以下四种:


(1) 从内存的某个格子中读取数据放入自己内部的寄存器Rx


(2) 把Rx的数据写入内存的某个格子中(会把原有数据覆盖)


(3) 进行数学运算和逻辑运算


(4) 根据条件进行跳转


数学运算就是加减乘除, 逻辑运算就是AND , OR 这样的基本运算,没接触过的暂时可以不用深究。


根据条件进行跳转就是从一个指令跳转到另外一个指令, 下文会详述。


2

从1加到100


现在我们试图用一个例子来揭开CPU和内存的神秘面纱, 这个例子就是把1, 2, 3, 4,..... 97, 98, 99, 100 这100个数字加起来 。


如果你看过数学王子高斯小时候的故事, 自然很简单,不就是 101 * 50 = 5050 吗 ?


作为码农, 我们需要用上面的简化计算机来解决这个问题: 我们需要精确的告诉CPU来指令, 让它去完成这个加法运算。


切记切记: 内存只是一个个可以读写的格子, CPU简单到只能做上面描述的4件事。


3

热身

在正式开始之前,我们先来热一下身,把你的思维切换一下, 用这个“简陋的”计算机计算一下 50 + 60 , 我门需要告诉CPU这些指令:


指令1 : 把数字50 放到编号为 #1 的格子里


指令2 : 把数字60 放到编号为 #2 的格子里


指令3 : 把格子#1的数字取出来,暂时放到CPU内部的寄存器R1中


指令4 :把格子#2的数字取出来, 暂时放到CPU内部的寄存器R2中


指令5 :把R1和R2的值相加, 结果放到R1中


指令6 :把R1的结果放到编号为 #1的内存格子里。


真是不容易啊, 因为CPU不能直接操作内存进行加法操作, 需要把数据从内存和CPU之间搬来搬去, 最后才完成了这么一个简单的运算。


4

正式出发


热身完毕,正式出发 !


回到那个从1加到100的题目, 我们的指令如下所示,CPU需要依次执行(除非遇到跳转指令), 直到结束:


指令1 : 把数字0 放到 编号为 #1 的格子里


指令2 : 把数字1 放到 编号为 #2 的格子里


指令3 : 把#1号格子的数取出放入CPU寄存器R1 (即 R1的初始值为0)


指令4 : 把#2号格子的数取出放入CPU寄存器R2 (即 R2 的初始值为1)


指令5 : 把R2的值和100 比较, 如果小于等于100,执行第6个指令, 否则执行第9个指令


指令6 : 把R1和R2的数据加起来, 结果放入R1


指令7 : 把R2的数值加1


指令8:  跳转到第5个指令


指令9: 把R1的值写回到 编号为 #1的格子里

(注:#1号格子的值就是结果)


这里提示一下: R2表示的就是从1到100这些数字,  R1存放的就是中间和。


现在,请你在脑子里边模拟一下这个过程, 看看程序能不能成功结束, 把最终结果放到#1号格子里。


如果觉得脑子不够用, 建议拿一个纸和笔,  把自己当成CPU, 把上面的这些指令手工的执行一遍, 体会一下这个过程。


如果你是非科班出身,并且能迅速的理解上面这些指令是如何完成从1到100的加法的, 恭喜你, 你很适合学习编程, 光明的前途在前面向你招手。


我们上面所说的指令和汇编非常相似, 这是一种非常贴近机器, 非常“低级”的计算机语言。


用这种语言来编写大型程序,会把人活活累死。


当然话也不能那么绝对, 对于那些大神级别的程序员来说, 汇编也是小菜一碟。  Ken Thompson 和 Dennis  Ritchie 不就用汇编写了第一版的Unix操作系统吗?  求伯君不就用汇编写了WPS吗?


对于普通人来说,大神们给我们创造了高级语言让我们使用, 如果我们用高级语言把上面的例子再写一遍, 你应该很容易能看明白了:


不要被之前的“低级”指令吓住, 这才是码农每天打交道的代码,不过这种高级语言写的代码最终也要被编译成“低级”语言代码, 最终交由CPU来执行, 编译后的机器语言,其实和上面的指令差不多。


5

思考


为什么要拿这个例子来挑战小白的大脑呢? 从本质上来说, 码农整天做的就是这样的事情, 告诉计算机使用这些指令去运算, 我们需要养成面向计算机的思维方式。


CPU能干的事情非常有限,笼统来说就是上面那四种, 但是我们现在上网、听歌、看视频、玩游戏,最终都会归结到这些操作中来, 这就是计算的本质。


此外, CPU是如此的冷酷, 以至于你的指令出一点点错误就不给你正确结果, 例如你把第3个指令中的“如果小于等于100”, 不小心写成了“如果小于100”, 

CPU当然不会告诉你程序中有问题,他只会冷冷的执行, 最后你会发现:这结果怎么不对呢?  


还有一个问题,CPU在运行的时候,从哪里取获得那些指令?


估计你已经想到了, 对,就是内存 ,指令也需要在内存中才能够被CPU访问到, CPU从内存读到指令以后,会进行分析(译码) , 看看这个指令是干什么的, 然后再进行运算。


所以我们的内存小格子中不仅仅存放的是数据,还存放着至关重要的程序指令! 我们需要告诉CPU第一条指令在什么地方, 然后CPU就可以疯狂的开始运行了:

这些指令在内存中肯定不是我们看到的自然语言, 而是二进制的表示。


那内存的数据又是从哪里来的?  肯定是硬盘了, 我们写好的程序会放在硬盘上, 在运行的时候才调入内存。 


最后,再次强烈推荐这本帮你透彻理解计算机软硬件到底是怎么结合工作的书籍:


(完)


码农翻身相关历史文章推荐:



操作系统

CPU阿甘

CPU阿甘之烦恼  

我是一个进程

我是一个键盘

我是一块硬盘(上)  

我是一块硬盘(下)

那些烦人的同步和互斥问题  

冯·诺伊曼计算机的诞生

Java EE

我是一个线程  

我是一个Java class

Java:一个帝国的诞生

JDBC诞生记

JDBC后传

一个不安分的JDBC驱动

JSP:一个装配工的没落

Javascript: 一个屌丝的逆袭

Spring本质系列(1) -- 依赖注入

Spring本质系列(2) -- AOP

Http 历险记(上)

Http 历险记(下)—Struts的秘密

三层架构和MVC那点事儿

Java帝国之 Java Bean(上)

Java帝国之 Java Bean(下)

Java帝国之 函数式编程 (上)

Java帝国之 函数式编程 (下)

计算机网络

我是一个路由器

我是一个网卡

TCP/IP之大明邮差

TCP/IP之大明内阁

TCP/IP之蓟辽督师

张大胖的socket

HTTP Server : 一个差生的逆袭

IE为什么把Chrome和火狐打伤了?

对浏览器村的第二次采访

节约标兵IE的自述

EMail诞生记

EMail诞生记(下)

数据库

小李的数据库之旅(上)

小李的数据库之旅(下)

张大胖学数据库

数据库村的旺财和小王



你看到的只是冰山一角, 更多精彩文章,尽在“码农翻身” 微信公众号, 回复消息"m"或"目录" 查看更多文章


有心得想和大家分享? 欢迎投稿 ! 我的联系方式:微信:liuxinlehan  QQ: 3340792577


公众号:码农翻身

“码农翻身”公众号由工作15年的前IBM架构师创建,分享编程和职场的经验教训。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存