前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS是如何计算 1+1=2 的?

JS是如何计算 1+1=2 的?

作者头像
LIYI
发布2019-09-02 16:00:54
1.8K0
发布2019-09-02 16:00:54
举报
文章被收录于专栏:艺述论专栏艺述论专栏

身为程序员多年,作者今天突然对这件事感到十分好奇了。我问计算机芸芸部件,1+1究竟是如何计算的,他们都茫然的看着我。

打开谷歌浏览器->Console面板,大脑向双手不停发送生物电信号,肌肉细胞大量钙分子游离到细胞外肌肉拉紧,钙分子回到细胞内肌肉又松开,钙分子来来回回进进出出多次,在大脑总枢纽指挥下,在多指配合下,最终完成了1、Shift+、1的键入,然后回车,输出如下:

谷歌浏览器返回了2。

作者问浏览器:“你小子是怎么知道1+1等于2的?纵观人类进化史,从学会使用石头,到学会结绳记数,用了100万年。你年纪轻轻28岁,是怎么知道1+1等于2的?”

浏览器说:“我不知道啊,是v8告诉我的。”

“v8是谁?是男是女?”

“非男非女,亦男亦女。v8是谷歌研发的JavaScript引擎,你发给我的JS代码,都是由他执行的。”

“把v8叫来,我有事问他。”

不一会儿,v8来到我面前。我问他:“你是怎么知道1+1等于2的?人类世界上最聪明的孩子降生时,都不知道1+1是等于2的。你是怎么知道的?”

“我并不知道1+1等于几,我所有结果都是基于您的输入给出的。”

作者问v8:“当浏览器把1+1发给你以后,你干了啥?”

“我就是进行了词法分析、语法分析,建立了语法树、符号表等...”

浏览器说:“这些都不要说了,这都是身为编译器/解释器的份内之事,大家都是这么干的,我解析Html标签也是这么干的。直接说你解析完了干了什么?”

v8道:“解析完了,我就使用了MacroAssembler库...”

浏览器说:"MacroAssembler库就是缩写为masm的汇编库吧,我去年在Strongtalk VM那里见过他,要知道Strongtalk VM可是大大鼎鼎的Java虚拟机HotSpot JVM的前辈呢!Java可是比JS快多了!"浏览器显得是一个见多识广的人。要知道全世界的www网页都展示都在他上面显示,他真的是见多识广。

但作者不喜欢浏览器自作聪明,“浏览器别打岔,v8你继续讲,使用masm干了什么?”

v8道:“masm提供了很多方法,基本和js是一一对应的,js语句是什么,就调用对应的masm方法。例如1+1这名js代码,对应调用masm的C++代码是这样的:

#define __ masm. __ mov(eax, 1) //在这里 __ 是一个宏,在预处理之后将被统一替换为“masm.”。这一句是将寄存器eax设置为1 __ add(eax, 1) //这一句将寄存器的值加1 __ ret(eax) //这里返回寄存值的值

(以上只是示例,伪代码不要当真)

上面是C++代码,在内存里生成机器码大概长这个样子:”

B8 01 00 00 00 ;mov eax,1 83 C0 01 ;add eax,1

浏览器道:“胡说!机器码都是二进制格式010110010这种的,你这种B8、C0是什么机器码?”

v8道:“我没有胡说啊!'B8 01 00 00 00'这是二进制机器码的16进制展示,人类使用16进制更方便阅读,但我和CPU交流都是以010110010这种二进制方式。”

这时CPU听到有人叫他的名字,按耐不住了。CPU问:“谁在说俺的大名!v8,那后面的'mov eax,1'是什么?我怎么从来没见你提过?”

v8道:“'mov eax,1'是机器码注释,是给人类大哥看的,我给你看的都是二进制字节码,是010110010这种。像mov它只是诸如1010这种汇编指令的代名词,人类写的是mov,汇编编译器译完就是1010了。

eax是寄存器地址,'mov eax,1'这句指令就是将寄存器的值设为1。同时,它下面那句'add eax,1'是将寄存器的数值加1。add与mov不就是你的两个指令吗,CPU大哥?如果我发错了指令,大哥从来都不曾理会我。”

CPU点点头。

浏览器继续问:“好啊v8,用户每天都骂我慢得像蜗牛,罪魁祸首原来在你这。码农都说你快,我每天看你却很慢。原来你是将js代码先转成了汇编代码,再将汇编代码转成为机器器,一件事转二道手续,这样能不慢吗?为什么不直接将js代码转为二进制机器码交给CPU大哥执行?”

“哈哈哈”,v8大笑道:“浏览器,你只知表面,不知就理。js是解析型语言,如何直接编译成机器码?如果是这样,它不就和Java一样,是编译型语言了吗?”

浏览器反驳道:“虽然是解释型语言,为什么不能先编译再执行?在Java版JS解释器rhino中,js脚本不是被编译为Java字节码执行的吗?”

作者觉得讨论有点跑偏了,道:“言归正传。v8,浏览器给你的js代码,你是读一行调用masm转化一行,还是读完了一起调用masm再转化的?”

v8说:“是一起转化的,但这一切都是在内存那里折腾的。我有两个助手,一个叫初级全码编译器(官名叫Full Code Generator),他将所有js代码依次调用masm全部在内存中走了一遍;另一个叫优化能手编译器(官名叫Crankshaft),他针对运行多次的代码,以全码编译器的编译结果为基础,再作一次优化编译,目的是使代码执行更快。”

这时内存说话了,“是啊,每次都把我折腾的晕头转向。别的exe文件,是先于我这里加载、后交给CPU运行,一次搞定,很干脆。唯有v8交给我的执行文件,连个名字都没有,忽长忽短,变化莫测。”

CPU说:“但是我感觉v8交给我的机器码和普通的exe文件机器码没有什么区别,在我这里他们都是合法公民。只要机器指令全部正确,我就能返回正确的运行结果。”

看来v8并不知道1+1为什么等于2,v8为了执行js快一点,大量占用了内存空间,是用”空间换时间”的方法,博得了“v8引擎执行快”的美名。具体为什么1+1等于2,还需要问问CPU。

作者对CPU道:“CPU,你说只要指令正确,你就能返回正确结果。那么v8将1+1的机器码传给你,你都做了什么?”

CPU道:“报告主人,我什么都没有做。我做的一切,都是让按照您的指令完成的。这一切都是您的智慧啊!”CPU态度很诚恳。

浏览器小声道:“嘘,马屁精!”

CPU不理会,继续说道:“首先,当我看到'mov eax 1',就知道这是叫我将值1移动到寄存器eax处。我有一个助理,叫指令指挥官,他负责指令的分类与调度。例如他看到指令是010100010010,首先从前4位0101判断,这是一个寄存器设置命令,于是就打电话通知寄存器老头来领取数据包裹;如果看到前4位是1010,就知道这是一个加法指令,就打电话通知算术运算单位的加法器来领取数据和任务,待加法器计算完了,他会将运算结果发给寄存器老头保存。”

这时浏览器对CPU如何计算的也起了好奇,问道:“不要说人话,讲机器语言,说人话我们听不懂。指令指挥官是如何给你的单位职员分派任务的?他看到0101,是怎么知道应该分派给寄存器老头的?”

“这么简单你都不明白吗?比如0101这4个bit,依次代表4个路口,每个路口有两个岔,0向左转,1向右转,这样0101一路走下来不就知道是哪个职员负责了。”

指令分派确实简单,关键还在加法器上。1+1等于几是他算出来的,于是作者问道:“CPU,那加法器是如何计算1+1的呢?”

CPU道:“这就不那么简单了。加法器并不知道1+1等于几。加法器是由半加器组成的,而半加器又是由一个异或门加一个与门组成的,如下所示是一个半加器:

(在上图中,A、B是输入,S是结果,C是进位结果。)

学过数学很容易理解,异或门的逻辑是这样的:

A

B

C

S

0

0

0

0

1

0

0

1

0

1

0

1

1

1

1

0

负负得负、正负得正、负正得正、负负得正,这就是异或门逻辑。如果说异或门电路有点复杂,那么异或门又可以由与非门表示:

(读者可以将1、0不同值分别代入A、B,验证异或门结果Q)

与非门的逻辑是这样的:

A

B

S

0

0

1

0

1

1

1

0

1

1

1

0

负负得正、负正得正、正负得正、正正得负。与非门简单电路可以是这样的:

x、y是两个开关。x、y的开状态为1,关状态为0。x、y相当于与非门中的A、B。x、y状态全开,以及任何一个状态为开,电路都是不通的。只有当x、y状态全为关,电路才是通的。

与非门可以由开关设计组成,异或门也可以由开关组成。异或门加一个与门组成了半加器,多个半加器串到一起,就组成了全加器,如下所示:

低位半加器的进位结果恰是高位半加器的输入,合在一起就组成了一个多位全加器。所以,我的加法运算能力也不是无限的,能算多大数字是由硬件决定的。”

这下明白了,CPU并不知道1+1等于2。之所以1+1能算出等于2,是人类在设计CPU的时候赋能给它的。而CPU内所有的运算,归根结底又都是开关的开合。从这点来看,计算机的鼻祖竟然是小小的开关。

浏览器问:“CPU,这样说来你的加法器都是由众多开关实现的。那减法运算、乘法运算、除法运算又是怎么实现的?”

CPU道:“减法在我这里也是加法,乘法是换算为多位加法累加的,除法又可以换算为乘法。所以,所有四则运算都是由加法实现的。包括文字与音频、视频信息处理,在我这里都是二进制的加减乘法与逻辑与非。”

浏览器又问:“那这样说,在你内部肯家有很多很多的开关喽?”

CPU说:“人类发明了一种双极型三极管,简称晶体管。在我内部,晶体管不多,也就有几十亿个吧。每个晶体管就相当于一个电路中的开关。”

原来作者在浏览器里简单敲一个1+1,CPU那里就要噼里啪啦开关个不停。

计算机并没有智能。我们从宏观上看,仿佛计算机拥有了智能一般,能处理很多复杂的问题,其实都是通过数以亿计的晶体管开关电路实现的,并且这种能力也都是人类赋予它的。

在人的大脑中,也有几十亿个神经元,像一个计算机一样。人为什么拥有智能?或者人根本也并不拥有智能,在上帝那里,我们的大脑也只是按照他老人家的设计表现开头状态而已?

2018年12月21日于北京

艺览无余


冬天来了,身上又胖了几斤,嗨...深深的惆怅

过两天印度的米叔要来北京了,我那么喜欢他的电影,我要不要见他?这几天一直为这事失眠,好忧愁。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-12-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 艺述论 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档