如果有人問你莽鸭,計(jì)算機(jī)和計(jì)算器的區(qū)別是什么吗伤,要怎么回答?
最簡(jiǎn)單的回答就是:
計(jì)算機(jī)相當(dāng)于巴貝奇發(fā)明的分析機(jī)硫眨。
計(jì)算器相當(dāng)于巴貝奇發(fā)明的差分機(jī)足淆。
不過今天可不是要說這個(gè)問題,拋出這個(gè)問題這是為了引出今天的主題礁阁,計(jì)算機(jī)大致是怎么運(yùn)算的巧号,對(duì)分析機(jī)和差分機(jī)有興趣的話可以自己查閱,這個(gè)值得你花些時(shí)間姥闭,因?yàn)樵谟?jì)算機(jī)領(lǐng)域丹鸿,不能只知道圖靈,而不知道巴貝奇棚品。
那么卜高,就根據(jù)上一篇的理論部分《JS基礎(chǔ)-數(shù)字-0.1+0.2!=0.3(一)》
弥姻,結(jié)合實(shí)物,來做一個(gè)最簡(jiǎn)單的加法器掺涛。
這是一個(gè)最簡(jiǎn)單的電路,我相信沒有人看不懂疼进,那我就不多說了薪缆。
這個(gè)裝置是一個(gè)簡(jiǎn)單的繼電器,原理非常簡(jiǎn)單:
符號(hào)V電壓在此代表通電的線路伞广。
當(dāng)輸入通電后拣帽,電磁鐵就會(huì)帶磁性,把帶彈性的金屬條吸下來連接B嚼锄,使V與B連通减拭,輸出就帶電了。
當(dāng)輸入斷電后区丑,電磁鐵失去磁性拧粪,帶彈性的金屬條回到了A,輸出就沒有電流了沧侥。
現(xiàn)在把兩者結(jié)合起來可霎,就出現(xiàn)了以下裝置:
這玩意有什么用?可以用來制作一些邏輯原件宴杀。
1. 與門電路(AND)
這個(gè)裝置叫做“與門電路”(AND)癣朗,就是左邊兩個(gè)輸入都有電流時(shí),右邊才有輸出旺罢,燈泡才能亮旷余。
js中的邏輯操作符 && 就是按照“與門”原理來的,&& 操作就是兩個(gè)操作值都為true扁达,結(jié)果才為真正卧,只要有一個(gè)為false,結(jié)果就為false罩驻。
2. 或門電路(OR)
這個(gè)裝置叫做“或門”(OR)穗酥,就是左邊兩個(gè)輸入只要一個(gè)有電流(或者都有電流),右邊就有輸出惠遏,燈泡就能亮砾跃。
js中的邏輯操作符 || 就是按照“或門”原理來的,|| 操作就是兩個(gè)操作值只要有一個(gè)為ture(或者同時(shí)為true)节吮,結(jié)果就為真抽高。
3. 與非門電路(NAND)
這個(gè)裝置叫做“ 與非門”(NAND),NAND 就是 NOT AND 的意思(AND 的 取反)透绩,左邊必須都輸入電流時(shí)燈泡才不亮翘骂,其余情況燈泡都亮壁熄。
這個(gè)裝置相當(dāng)于js中,使用 && 操作完之后再取反, !( A && B)
4. 或非門電路(NOR)
這個(gè)裝置叫做“ 或非門”(NOR),NOR 就是 NOT OR 的意思(OR 的 取反)碳竟,左邊當(dāng)兩個(gè)輸入只有當(dāng)都沒有電流時(shí)草丧,燈泡才亮,其余情況燈泡不亮莹桅。
這個(gè)裝置相當(dāng)于js中,使用 || 操作完之后再取反, !( A || B)
注:本章并不涉及或非門電路(NOR)的使用昌执,但是為了體現(xiàn)完整性,需要介紹诈泼,特此說明懂拾。
了解之后,需要簡(jiǎn)化一下這些電路铐达,因?yàn)樵趫D上作業(yè)時(shí)岖赋,畫起來很不方便。
嘗試用邏輯電路做2進(jìn)制加法
現(xiàn)在要計(jì)算 15 + 15 = 30瓮孙,這個(gè)很容易唐断,那么2進(jìn)制加法該怎么做?
首先肯定要把 15 轉(zhuǎn)化成2進(jìn)制 為 1111(2)衷畦,然后套用10進(jìn)制的豎式加法方式來計(jì)算栗涂,如下
這種計(jì)算的特點(diǎn)是:同位相加,并且從低位開始祈争,求出當(dāng)前位的結(jié)果(和)斤程,和進(jìn)位的值。
進(jìn)位的情況只有一種:
同位都為1時(shí)菩混,進(jìn)位1忿墅。其他情況都進(jìn)位0;
結(jié)果(和)的情況稍微復(fù)雜一點(diǎn):
同位都為1時(shí)沮峡, 結(jié)果(和) 0疚脐;
同位都為0時(shí), 結(jié)果(和) 0邢疙;
同位只有一個(gè)1時(shí)棍弄,結(jié)果(和)1;
把有電流代表1疟游,沒有電流代表0呼畸,對(duì)于進(jìn)位操作,一個(gè)與門電路就可以搞定颁虐。
但是蛮原,同位相加的結(jié)果(和)并沒有哪一個(gè)單一邏輯電路能夠?qū)崿F(xiàn),需要重新組裝一個(gè)邏輯電路才可以另绩。
5. 異或門電路(XOR)
異或門電路由三個(gè)基礎(chǔ)邏輯電路組成(或門花嘶,與非門,與門)蹦漠,這個(gè)需要好好捋順下思路椭员,從頭到尾把 00, 01笛园,10拆撼,11四種電流輸入的情況走一遍,一點(diǎn)也不難喘沿。
這樣的輸出結(jié)果就和想要的2進(jìn)制加法同位相加結(jié)果一致了。
6. 半加器
由此竭贩,可以組裝出2進(jìn)制加法中蚜印,一個(gè)位的結(jié)果(和)和進(jìn)位的裝置,稱之為“半加器”留量。
為什么叫“半加器”窄赋?因?yàn)樗€只是一個(gè)半成品,先求個(gè)和來驗(yàn)證一下楼熄,還是拿 15 + 15 舉例吧
現(xiàn)在需要一個(gè)輸入端有三個(gè)入口的裝置忆绰,兩個(gè)同位的值入口 + 進(jìn)位值入口,不用擔(dān)心可岂,有辦法解決错敢。
7. 全加器
這一塊稍微有點(diǎn)繞,還是從頭一步一步來缕粹,
1稚茅、第一個(gè)半加器沒啥好解釋的,他會(huì)輸出同位的結(jié)果值(和)和進(jìn)位值平斩。
2亚享、假設(shè)上一位有進(jìn)位輸入1,那么這個(gè)1绘面,一定是與當(dāng)前位的結(jié)果值(和)在第二個(gè)半加器處相加欺税,不能和當(dāng)前為的進(jìn)位值相加,對(duì)吧揭璃,這是必須的晚凿,因?yàn)槭謱懾Q式的邏輯就是這樣的。
3塘辅、第二個(gè)半加器的結(jié)果值(和)就是最終的結(jié)果值(和)了晃虫。
4、這一步最重要扣墩,兩個(gè)半加器的進(jìn)位輸出居然用一個(gè)或門連接哲银,為什么扛吞?你可以認(rèn)真的思考一下,第一個(gè)半加器和第二個(gè)半加器的進(jìn)位輸出荆责,會(huì)同時(shí)為1嗎滥比?這是不可能發(fā)生的事!做院!
8. 加法器
如果要計(jì)算1111(2) + 1111(2),就可以使用4個(gè)全加器(FA)連接來完成運(yùn)算盲泛,設(shè),上排4個(gè)加數(shù)從左到右依次為 A3键耕、A2寺滚、A1、A0屈雄,下排4個(gè)加數(shù)從左到右依次為 B3村视、B2、B1酒奶、B0蚁孔,那么如下圖依次輸入全加器,就可以得到結(jié)果值惋嚎。
那么這就組成了一個(gè)4位的加法器杠氢,計(jì)算機(jī)都是8位為一個(gè)基本單元的,所以也可以組裝成標(biāo)準(zhǔn)的8位加法器另伍。
上圖中A輸入為一個(gè)8位2進(jìn)制加數(shù)鼻百,B輸入也是一個(gè)8位2進(jìn)制加數(shù),只不過排布不一樣质况,原理和最開始的4位加法器一致愕宋,它可以用作兩個(gè)8位2進(jìn)制加數(shù)的求和。
如果需要位數(shù)更大的加法器结榄,以便一次性計(jì)算更大的加數(shù)中贝,比如16位加法器,可以向如下這樣把兩個(gè)8位加法器相連臼朗。
到這邻寿,是不是可以聯(lián)想到32位,64位视哑,甚至更多位的加法器如何拼裝了呢绣否?
當(dāng)然,現(xiàn)代計(jì)算機(jī)已經(jīng)不使用繼電器了挡毅,從繼電器蒜撮,到電子管,再到晶體管,不過無論是什么材料器件段磨,他們的計(jì)算原理都是這樣的取逾。
9. 定點(diǎn)機(jī)
當(dāng)然,在此展示的只是整數(shù)的加法運(yùn)算苹支,但小數(shù)的加法運(yùn)算也依然如此砾隅,如果計(jì)算:
0.101(2) + 0.001(2),只需要計(jì)算101 + 001 即可债蜜,把計(jì)算小數(shù)的加法器叫做小數(shù)定點(diǎn)機(jī)晴埂,之所以叫定點(diǎn)機(jī),是因?yàn)?.是不考慮的寻定,直接默認(rèn)在定點(diǎn)機(jī)的最前面
例如使用8位小數(shù)定點(diǎn)機(jī)計(jì)算0.101(2) + 0.001(2)儒洛,那么兩個(gè)數(shù)要分別轉(zhuǎn)換成
1010 0000 和 0010 0000,然后再參與運(yùn)算狼速,如果進(jìn)位了晶丘,可以將進(jìn)位的1輸出到其他寄存器中,或者直接舍棄唐含,根據(jù)具體需要而定。
而前文展示的其實(shí)就是整數(shù)定點(diǎn)機(jī)的運(yùn)算沫浆,整數(shù)定點(diǎn)機(jī)默認(rèn)小數(shù)點(diǎn)在最右邊捷枯,和小數(shù)定點(diǎn)機(jī)剛好相反。
注意:整數(shù)定點(diǎn)機(jī)和小數(shù)定點(diǎn)機(jī)只是叫法上方便區(qū)分专执,實(shí)際上邏輯電路配置是一樣的淮捆。這一點(diǎn)你應(yīng)該想到。
10. 浮點(diǎn)數(shù)運(yùn)算
而對(duì)于既有整數(shù)又有小數(shù)的原始數(shù)據(jù)(稱之為浮點(diǎn)數(shù))本股,如果使用定點(diǎn)機(jī)進(jìn)行運(yùn)算攀痊,需要設(shè)定一個(gè)比例因子,數(shù)據(jù)按比例因子縮小成定點(diǎn)小數(shù)或擴(kuò)大成定點(diǎn)整數(shù)再參加運(yùn)算拄显,結(jié)果輸出時(shí)再按比例折算成實(shí)際值苟径。
比例因子必須選擇恰當(dāng)。選擇不當(dāng)躬审,將會(huì)影響運(yùn)算精度棘街,或者會(huì)使運(yùn)算結(jié)果超出機(jī)器所能表示的數(shù)據(jù)范圍,即出現(xiàn)溢出承边。
例如:
在定點(diǎn)小數(shù)機(jī)器中計(jì)算 11.01+10.01 選擇比例因子=0.01遭殉,可將兩操作數(shù)變換為 0.1101+0.1001 但 0.1101+0.1001=1.0110,運(yùn)算結(jié)果不是純小數(shù)博助,出現(xiàn)了機(jī)器數(shù)不能表示的數(shù)险污,即出現(xiàn)了正溢出。 如果選擇比例因子 =0.001富岳,可將兩操作數(shù)變換為 0.01101+0.01001 則運(yùn)算結(jié)果 0.01101+0.01001=0.10110 為正常結(jié)果蛔糯。將0.10110除以比例因子拯腮,可得到正確結(jié)果 101.10。
這種計(jì)算浮點(diǎn)數(shù)的方式效率極其低下渤闷,現(xiàn)代計(jì)算機(jī)早已使用浮點(diǎn)運(yùn)算器來處理浮點(diǎn)數(shù)運(yùn)算疾瓮,且JS所有數(shù)字都是使用浮點(diǎn)數(shù)運(yùn)算器來進(jìn)行運(yùn)算的(當(dāng)然也就包含0.1 + 0.2的運(yùn)算)。浮點(diǎn)運(yùn)算器的邏輯配置極其復(fù)雜飒箭,有自己獨(dú)立的運(yùn)算硬件狼电,本人知識(shí)儲(chǔ)備有限,就不展開說明了弦蹂,但是肯定是建立在前面所說的基本邏輯之上的肩碟。未來可能會(huì)寫浮點(diǎn)運(yùn)算器硬件相關(guān)內(nèi)容。
*11. 如何計(jì)算減法
這一部分說明補(bǔ)碼由來相關(guān)凸椿,因?yàn)樵诘谒恼聲?huì)涉及到補(bǔ)碼概念削祈,所以和0.1 + 0.2 的主題有一定關(guān)系。但這不是必須的脑漫,完全可以跳過髓抑。
前面配置的邏輯電路是針對(duì)于加法的,但是減法的邏輯電路如何實(shí)現(xiàn)呢优幸。
補(bǔ)數(shù)
如果要確定兩個(gè)數(shù)是不是互為補(bǔ)數(shù)吨拍,需要有一個(gè)參照,或者說需要一個(gè)標(biāo)量网杆,比如:
4 和 3 互為補(bǔ)數(shù)羹饰,是相對(duì)于標(biāo)量7來說的,一般稱作“4的7的補(bǔ)數(shù)為3” 或者 “3的7的補(bǔ)數(shù)為4”碳却,因?yàn)?4 + 3 = 7队秩。如果標(biāo)量是 8, 4 和 3 就不是互為補(bǔ)數(shù)昼浦。
同理:
2的10的補(bǔ)數(shù)為8馍资,
2的100的補(bǔ)數(shù)為98。
21的1000的補(bǔ)數(shù)為979关噪。
7的9的補(bǔ)數(shù)為2迷帜。
7的99的補(bǔ)數(shù)為92。
注意色洞,補(bǔ)數(shù)沒有正負(fù)的概念戏锹。
補(bǔ)數(shù)有啥用?
口算:
997 + 973 = 火诸?
(1000 - 3) + 973 = 1970
這個(gè)是在口算數(shù)學(xué)加法的時(shí)候用的方法锦针,在計(jì)算機(jī)中利用補(bǔ)數(shù)能干啥呢,做減法。
145 - 98 = 奈搜?
在這個(gè)減法中悉盆,一定要用到借位,如果要使用邏輯電路計(jì)算的話馋吗,要先判斷同位數(shù)值的大小焕盟,小的話就要加上一個(gè)值,上一位呢就要減去一個(gè)值宏粤,非常復(fù)雜脚翘,如果不需要借位做減法就好了對(duì)吧,那么就可以用到補(bǔ)數(shù)概念绍哎。
= 145 - (999 - 901
)
= 145 + 901
- 999
= 1045 + 901
+ ( 1 - 1000)
= 1047 - 1000
= 47
估計(jì)你已經(jīng)繞暈了来农,磨磨唧唧的這么算到底有啥好處?目的只有一個(gè)崇堰,就是不用借位算減法沃于,901
就是 98 的 999 的補(bǔ)數(shù)。為啥選擇999呢海诲?因?yàn)?0進(jìn)制中繁莹,沒有單個(gè)數(shù)字比9更大了,又因?yàn)?145 為 3位特幔,所以選擇 999蒋困。這樣做減法,一定不會(huì)借位敬辣。
轉(zhuǎn)化成2進(jìn)制計(jì)算呢?
在這里零院,原來的補(bǔ)數(shù)標(biāo)量 999 要換成 11111111溉跃,因?yàn)?進(jìn)制中,單個(gè)數(shù)字沒有比1更大的了告抄,又因?yàn)?145 轉(zhuǎn)化成 2進(jìn)制為 8位撰茎,所以要用 11111111。
98轉(zhuǎn)化成2進(jìn)制為 01100010打洼。
01100010 的 11111111 的補(bǔ)數(shù)龄糊,就是用 11111111 - 01100010,到這里先停一下募疮,仔細(xì)看這個(gè)2進(jìn)制減法炫惩。
這個(gè)減法實(shí)際上就是把 01100010 各位取反了,這就是2進(jìn)制的神奇所在阿浓,也是2進(jìn)制減法的精髓所在他嚷,因?yàn)樽鲆粋€(gè)取反的電子原件實(shí)在太容易了。
這個(gè)玩意叫做“反向器”,它不算是邏輯電路筋蓖,但是同樣重要卸耘,可以用它來做取反的操作。
類似于js中的一元操作符 !
= 1001 0001
- ( 1111 1111
- 1001 1101
)
= 1001 0001
+ 1001 1101
- 1111 1111
= 1001 0001
+ 1001 1101
+ ( 1
- 1 0000 0000
)
為什么把 -
1111 1111
分解成1
-1 0000 0000
粘咖?
按照上述方法計(jì)算減法時(shí)蚣抗,如果被減數(shù)
比減數(shù)
數(shù)值大,結(jié)果一定是1 xxxx xxxx
(x表示1或者0的值)的9位2進(jìn)制數(shù),不信你可以驗(yàn)證一下o( ̄︶ ̄)o前塔。
1 xxxx xxxx
-1 0000 0000
=xxxx xxxx
茄菊。
這樣,計(jì)算結(jié)果的進(jìn)位輸出1
两蟀,忽略不計(jì)就行了。因此震缭,現(xiàn)在這個(gè)計(jì)算方法赂毯,只能計(jì)算
被減數(shù)
比減數(shù)
大的情況,這點(diǎn)要注意拣宰。
在這又得停一下党涕,因?yàn)榭梢允褂眉臃ㄆ鱽硗瓿珊罄m(xù)操作了。
你可以驗(yàn)證一下和輸出的 0010 1111
是不是 47巡社。CO輸出的進(jìn)位1可以和要減去的 1 0000 0000
抵消掉膛堤。如果 減數(shù)
比 被減數(shù)
數(shù)值大,CO輸出就是0晌该,此時(shí)的計(jì)算結(jié)果錯(cuò)誤肥荔,就需要特殊處理了。
如何優(yōu)化
初始時(shí)的進(jìn)位輸入1其實(shí)大可不必朝群,可以把他直接合并到補(bǔ)數(shù)10011101
中:
1001 0001
+ (1001 1101
+ 1
) - 1 0000 0000
得1001 1110
燕耿,這樣進(jìn)位輸出就節(jié)省出來了,在輸入數(shù)值時(shí)直接輸入1001 1110
即可姜胖。
原碼 和 補(bǔ)碼
計(jì)算機(jī)的真實(shí)計(jì)算情況與所展示流程還是有點(diǎn)區(qū)別誉帅,先來看下什么是原碼。
原碼:計(jì)算機(jī)中只能識(shí)別0和1右莱,不過也巧了蚜锨,數(shù)字也只有正負(fù)2種,沒有第三種慢蜓,剛好合適亚再,那么正負(fù)數(shù)也就能用0和1來區(qū)分〕柯眨科學(xué)家們規(guī)定针余,0代表正數(shù)饲鄙,1代表負(fù)數(shù),放在數(shù)值的最高位上圆雁,也就是最左邊忍级。
拿8位為例,拿出一個(gè)位來表示正負(fù)伪朽,就還剩7位來表示數(shù)值轴咱,7位能表示 27 = 128 種狀態(tài),從0開始就是0 ~ 127烈涮,所以8位能代表的數(shù)值為 -127 ~ ±0 ~ 127朴肺,如下圖所示。
原碼不能直接參與運(yùn)算坚洽,因?yàn)?1111 1110
+ 0000 0001
= 1111 1111
戈稿,-126 + 1居然等于-127,這明顯不對(duì)啊讶舰,所以原碼一般用于輸入輸出數(shù)據(jù)時(shí)使用鞍盗,因?yàn)槿搜劭梢院苋菀讌^(qū)分?jǐn)?shù)值,但是計(jì)算機(jī)不能運(yùn)算跳昼。那么運(yùn)算使用什么編碼般甲?
補(bǔ)碼:計(jì)算機(jī)運(yùn)算使用補(bǔ)碼,補(bǔ)碼的規(guī)則是在原碼的基礎(chǔ)上變形而來:
①如果值為正數(shù)鹅颊,那么補(bǔ)碼就是原碼本身敷存。
②如果值為負(fù)數(shù),那么補(bǔ)碼就是其值絕對(duì)值的原碼各位取反堪伍,然后 + 1锚烦。
補(bǔ)碼和原碼對(duì)比一下:
相同點(diǎn):補(bǔ)碼和原碼都是使用 0代表正數(shù),1代表負(fù)數(shù)
不同點(diǎn):原碼存在±0帝雇,而補(bǔ)碼只有一種0涮俄,就是機(jī)器0(所有位數(shù)都為0稱為機(jī)器0),原碼中的-0在補(bǔ)碼中表示一個(gè)絕對(duì)值最大的負(fù)數(shù)摊求。
補(bǔ)碼最大的優(yōu)點(diǎn)就是:無論加法和減法,都統(tǒng)一按照加法來計(jì)算刘离,但是注意室叉,
補(bǔ)碼與補(bǔ)碼相加,結(jié)果依然是補(bǔ)碼硫惕。
找?guī)讉€(gè)例子試一下:
+127 + (-128)
= 0111 1111
+ 1000 0000
= 1111 1111
結(jié)果1111 1111
就是一個(gè)補(bǔ)碼茧痕,但是我們還是習(xí)慣于看原碼。
補(bǔ)碼轉(zhuǎn)換成原碼和原碼轉(zhuǎn)化成補(bǔ)碼規(guī)則差不多:
①如果符號(hào)位是0恼除,那么這個(gè)補(bǔ)碼就是原碼踪旷,
②如果符號(hào)位是1曼氛,就符號(hào)位不變,各位取反令野,然后 + 1
1111 1111(補(bǔ))
=> 1000 0000
+ 1
=> 1000 0001(原)
舀患,最終結(jié)果為 -1。
疑惑
①兩個(gè)負(fù)數(shù)相加气破,進(jìn)位輸出一定為1聊浅,那么這個(gè)進(jìn)位1怎么辦?
答:直接忽略不計(jì)现使,這也正是保證補(bǔ)碼計(jì)算準(zhǔn)確的關(guān)鍵低匙。
②如果兩個(gè)數(shù)相加大于127或者小于128了怎么辦?
答:這種情況就是溢出碳锈,溢出也很好判斷顽冶,兩個(gè)正數(shù)相加,如果符號(hào)位變化了售碳,就說明溢出了强重,兩個(gè)例子:
127 + 127
= 0111 1111
+ 0111 1111
= 1111 1110
正數(shù)相加,符號(hào)位變化了团滥,就是向上溢出竿屹。
-128 - 128
= 1000 0000
+ 1000 0000
= 0000 0000(超出8位的直接舍棄)
負(fù)數(shù)相加,符號(hào)位變化了灸姊,也是向上溢出拱燃。
8位范圍內(nèi)的兩個(gè)補(bǔ)碼相加,如果一個(gè)為正數(shù)力惯,一個(gè)為負(fù)數(shù)碗誉,是不可能發(fā)生溢出的。想想是不是這么回事父晶。加法沒有向下溢出的情況哮缺。
在 145 - 98 = ?這個(gè)例子中甲喝,實(shí)際上對(duì)于 -98 的處理就是補(bǔ)碼尝苇,只不過沒有加入符號(hào)位的概念,計(jì)算機(jī)中并不是配置不出通過“借位”實(shí)現(xiàn)的減法器埠胖,而是沒有必要有糠溜,這一點(diǎn)希望你能體會(huì)到,那么關(guān)于補(bǔ)碼和原碼的說明就到這吧直撤,如果還有疑惑可以查閱相關(guān)資料非竿,網(wǎng)上相關(guān)的資料還是很多的。
12. 總結(jié):
本章所寫內(nèi)容無疑是“管中窺豹”谋竖,根本是讓大家對(duì)計(jì)算機(jī)硬件運(yùn)算了解一二红柱,下一章將進(jìn)入0.1 + 0.2 的最主要部分承匣,IEEE754浮點(diǎn)數(shù)運(yùn)算標(biāo)準(zhǔn)的說明。
對(duì)于乘法锤悄、除法如何計(jì)算韧骗,因?yàn)椴簧婕?.1 + 0.2運(yùn)算,時(shí)間允許的話铁蹈,在本系列最后會(huì)簡(jiǎn)要說明宽闲。