知乎問題:如何讓不懂編程的人感覺到編程的魅力?
問一個相似的問題:「如何讓不懂籃球的人感覺到籃球的樂趣?」java
很明顯,答案取決於人。 git
對於某些人來講,編碼多是乏味而艱鉅的,但對於有些人則是很是有趣且有益的。程序員
一般狀況下,編寫好代碼以後,咱們很難評判編碼的過程是無聊仍是有趣的。github
可是咱們能夠經過更好地瞭解 「計算機編程是什麼」,所以您能夠本身來評判這是否讓你感到樂趣。算法
就當代的發展水平來講,只要有電的東西就會涉及到編碼;
衣食住行是人類的基本需求,世界各地都有紡織和織機的發明。編程
如何提高紡織的效率,成爲一個很重要的課題。segmentfault
與 「針織物」 不一樣,「機織物」 由兩條或兩組以上的相互垂直的兩個系統紗線或絲線構成,縱向的紗線 叫 經紗,橫向的紗線 叫 緯紗。架構
經過兩條線不一樣規律的交錯,就會造成不一樣的顏色和排列的變化,也就會帶來不一樣的紋樣。app
最原始的織機是手動完成的。
後來人們發現,織物紋樣的變化老是按照必定規律排列完成的,到了戰國時期,就發明了 多綜式提花織機,經過 綜框 來完成這一項工做:
這或許就是最原始的 編碼:經過把 提起規律相同的經紗 穿入 同一個綜框的綜絲 中,來達到當某一個綜框提起時 (經過腳踏板完成),表達某一個特定紋路的線被提起,也就完成了 特定紋路的編織,加快了工做效率。
不過採用綜框也有一個明顯的限制,那就是 沒法織出比較複雜的紋樣,由於紋樣複雜則表明着須要更多的經緯紗以及經紗提高的規律更復雜,意味着可能引入成百上千次緯紗才能完成一個循環。
若是仍然採用綜框控制紗線提高,則可能須要成百上千個綜框,這在機械上實現是很是困難的,所以便有了 束綜提花織機。
束綜提花織機沒有綜框,而是被 設計成兩層,每一根經紗會穿入綜絲中實現 單獨的控制,上層 的人將須要提起的經紗提起,而 下層 的人則再經紗提起後經過梭子將緯紗送入織口,並用打緯裝置將引入的緯紗打牢。
然而一般來講,這類織機上會有成千上萬根緯紗,紋樣複雜,因而聰明的老祖宗們發明了 花本:
簡單來講,花本存儲了紋樣信息。
圖中花本的豎線鏈接穿入了經紗的綜絲,橫線存儲了每一次引入緯紗時提花信息,當豎線越過橫線覆蓋在橫線前方時,代表對應的經紗要被提起。
這就有點兒 編碼規則 的意思。
上面說到的束綜提花織機雖然是一大進步,但可想而知的是,它仍然效率緩慢而且織布工人的勞動量很是大,也很是辛苦。
時間來到 18
世紀的歐洲。1725
年,布喬 開拓性的使用 打孔紙帶 來控制經線的提起和放下,從而讓織出花樣成爲一種半自動化的工做:
歷史上第一次,機器可以讀出存儲介質中的內容,而且照其行事。
在布喬提出構想 65
後的 1790
年,約瑟夫·瑪麗·雅卡爾 根據前人的成果設計了新式織機,最終於 1805
年完成了首臺 自動提花織機:
雅卡爾將 穿孔紙帶 改進爲 穿孔卡片,根據紋樣圖案在卡片上打孔,經過孔的有無 帶動一系列機械運動裝置來 控制經紗的提高,一張卡片對應循環內一次引緯時經紗提高的信息,引緯完成後,可經過腳踏板控制卡孔卡片轉動,下一張卡片翻轉至工做位置以控制新一次引緯的提花:
雅卡爾織機大幅度節省了時間和工做量 (全自動且效率是以前的二十五倍),並且只需一位工人,很快就被普遍使用在工廠生產中,雅卡爾也榮獲了拿破崙授予的榮譽勳章。
穿孔卡片控制織物紋樣的設計成爲了程序設計思想的萌芽,爲信息技術的發展開展了一條新的道路。
時間來到 19
世紀初,法國人 巴貝奇 (Chanles Badbbage) 在賈卡織機的啓發下,設計並製造了 差分機。
18
世紀末,法國政府在開創米制以後,決定在數學中統一採用十進制,竟奇葩地想把本來 90
度的直角劃分紅 100
度、把本來 60
秒的 1
分鐘劃分紅 100
秒,儘管從如今看來這樣的想法絕逼是一種倒退,但他們在當時真就實施了。這一改制帶來的不光是人們在使用時直觀上的彆扭,本來製做好的數學用表 (如三角函數表) 都須要所有重製。
法國政府將這項喪心病狂的工程交給了 數學家普羅尼 (Gaspard de Prony),普羅尼正頭疼着要如何才能完成這項艱鉅的任務,忽然想起著名經濟學家 亞當·斯密 (Adam Smith) 的那本《富國論》,他決定採用書中提出的 勞動分工 的作法,將製表的工做人員分紅三組:
第三組的工做簡單到什麼程度,就是他們甚至都不知道本身正在算什麼玩意兒,事實上他們的文化程度大部分都不高,裏頭好多都是理髮師、失業人員什麼的。可見即使文盲都能完成的計算,在那個時代仍是得依靠人力去作。
而爲了保證用表的正確性,普羅尼要求 每一個數至少算兩遍,而且 要在法國的不一樣地點用不一樣的方法計算。這項勞民傷財的工程整整進行了十年才完成,然而不幸的是,最終的表裏仍然有錯。說到這一點,能夠說,那個時代基本沒有一版數學用表是徹底正確的,有些版本甚至錯誤百出,要知道數學用表出錯有時後果會很嚴重,好比航海表一出錯就可能直接致使船毀人亡。
巴貝奇 在瞭解到普羅尼的事蹟後淚流滿面,決心要作一套徹底正確的數學用表,爲達目的,他嘗試了各類減小錯誤的手段,好比調整紙張和墨水的顏色以提升數字的識別度,直接拿現有的多個版本的表進行謄抄、比對、讓不一樣人員反覆校對,在 1827
年出版了一個版本,結果裏頭仍是有錯。只要是人爲的就沒有完美的,巴貝奇完全跪了,他發誓要造一臺機器,讓機器去生產數學表。
這就是史上著名的 差分機 了。
倫敦科學博物館·差分機設計圖紙&半成品:
儘管沒能親手實現差分機,但巴貝奇並不會氣餒,或者說他原本就是根本停不下來的那種人。明知實現不了,巴貝奇仍在一刻不停地改進着本身的設計,直到有一天,他構思出了一種空前的機器——分析機,正式成爲現代計算機史上的第一位偉大先驅。 (Father of computing)
1834
年,分析機概念誕生之際,巴貝奇本身都爲之感到無比震驚。在此以前,任何一臺計算機器都只能完成其被預約賦予的計算任務,要麼是簡單的加減乘除,要麼像差分機那樣只能作差分運算,它們都屬於 calculator
,而分析機纔是真正的 computer
,它不侷限於特定功能,而居然是可編程的,能夠用來 計算任意函數——現代人不管如何也沒法想象在一坨齒輪上寫程序是怎樣一種體驗吧!
巴貝奇設計的分析機主要包括三大部分:
以上三部分,加上巴貝奇並無疏漏的輸入輸出設備,咱們驚訝地發現,分析機的組成部分和如今馮·諾依曼架構所要求的五大部件如出一轍!
巴貝奇另外一大了不得的創舉就是將 穿孔卡片(punched card) 引入了計算機器領域,用於控制數據輸入和計算,從那時起,到第一臺電子計算機誕生爲止,期間幾乎全部的數字計算機都使用了穿孔卡片。
整個分析機就是在相似這樣的齒輪和拉桿做用下實現可編程運算的:先從數據卡片讀入數據到存儲器,再將存儲器中的數據傳輸到運算器,運算器算完後又將數據傳回存儲器。
惋惜的是,巴貝奇窮其一輩子也沒能真正把分析機作出來,留給後世的又是一臺模型機和兩千多張圖紙,以及這樣一段遺言:
「若是一我的不因我一輩子的借鑑而卻步,仍然一往直前製成一臺自己具備所有數學分析能力的機器……那麼我願將個人聲譽絕不吝嗇地讓給他,由於只有他可以徹底理解個人種種努力以及這些努力所得成果的真正價值。」
倫敦科學博物館·分析機設計圖紙&模型機:
從 1790
年開始,美國每 10
進行一次人口普查。百年間,隨着人口繁衍和移民的增多,從 1790
年的 400
萬不到,到 1880
年的 5000
多萬,人口總數呈爆炸式地增加。
不像如今這個的互聯網時代,人一出生,各類信息就已經電子化、登記好了,甚至還能數據挖掘,你沒法想象,在那個計算設備簡陋得基本只能靠手搖進行四則運算的 19
世紀,千萬級的人口統計就已經成了當時政府的 「不能承受之重」。
1880
年開始的第 10
次人口普查,歷時 8
年才最終完成,也就是說,他們在休息兩年以後就要開始第 11
次普查了,而這一次普查,須要的時間恐怕要超過 10
年,那第 12
次、13
次呢?原本就是 10
年一次的統計,若是每次耗時都在 10
年以上,這件事情就變得沒有意義了。
這可愁煞了當時的人口調查辦公室,他們決定面向全社會招標,尋求能減輕手工勞動、提升統計效率的發明。正所謂機會都是給有準備的人的,一位畢業於哥倫比亞大學的年輕人 赫爾曼·霍爾瑞斯 (Herman Hollerith) 帶着他在 1884
年申請的專利從衆多方案中脫穎而出。
他發明的機器叫 製表機 (tabulator/tabulating machine),顧名思義,就是專門用來製做數據統計表的機器。製表機主要由示數裝置、穿孔機、讀卡裝置和分類箱組成。
示數裝置包含 4
行、10
列共 40
個示數錶盤,每一個盤面被均勻地分紅 100
格,並裝有兩根指針,和鐘錶十分相像,「分針」 轉一圈可計 100
,「時針」 轉一圈則計 10000
。可見,整個示數裝置能夠表達很龐大的數據。
製表機的工做是圍繞穿孔卡片展開的:操做員先使用穿孔機制做穿孔卡片,再使用讀卡裝置識別卡片上的信息,機器自動完成統計並在示數錶盤上實時顯示結果,最後,將卡片投入分類箱的某一格中,進行分類存放,以供下次統計使用。
此前的某一天,霍爾瑞斯正在火車站排隊檢票,目光不經意落到檢票員手中咔咔直響的打孔機上。他發現,檢票員會特地根據乘客的性別和年齡段,在車票的不一樣地方打孔。愈來愈多的人過檢,他進一步確認了這個規律。一個靈感朝他襲來:若是有一張更大的卡,上面有更多的位置能夠打孔,就能夠用來表示更多的身份信息,包括國籍、人種、性別、生日等等。
這就是用在 1890
年人口普查中的穿孔卡片,一張卡片記錄一個居民的信息。卡片設計長約 18.73cm
,寬約 8.26cm
,正好是當時一張美圓紙幣的尺寸,由於霍爾瑞斯直接用財政部裝錢的盒子來裝卡片。
卡片設有 300
多個孔位,與雅卡爾和巴貝奇的作法同樣,靠每一個孔位打孔與否來表示信息。儘管這種形式很有幾分二進制的意味,但當時的設計還遠不夠成熟,並無用到二進制真正的價值。舉個例子,咱們如今通常用 1
位數據就能夠表示性別,好比 1
表示男性,0
表示女性,而霍爾瑞斯在卡片上用了兩個孔位,表示男性就其中一處打孔,表示女性就在另外一處打孔。其實性別還湊合,表示日期時浪費得就多了,12
個月須要 12
個孔位,而常規的二進制編碼只須要 4
位。固然,這樣的侷限也與製表機中簡單的電路實現有關。
細心的讀者可能發現卡片的右下角被切掉了,那不是殘缺,而是爲了不放反而專門設計的,和如今的二維碼只有 3
個角是一個道理。
這類實用的細節設計在穿孔機上表現得更爲出色。下圖爲一位操做員正在使用穿孔機給卡片打孔的情景,她並不須要在卡片上吃力地搜尋孔位,而是直接對着孔距更大的操做面板打孔,一根槓桿將二者的孔位一一對應。操做面板還作成了弧形,很有一分現在人體工程學鍵盤的風姿。
在製表機前,穿孔卡片(或紙帶)多用於存儲指令而不是數據。比較有表明性的,一是雅卡爾提花機,用穿孔卡片控制經線提沉;二是自動鋼琴,用穿孔紙帶控制琴鍵壓放。美劇《西部世界》中,每次故事循環的開始,都會給一個自動鋼琴的特寫,彈奏起看似寧靜安逸、實則詭異違和的背景樂。
是霍爾瑞斯將穿孔卡片做爲 數據存儲介質 開來,並開啓了一個嶄新的 數據處理紀元。後來人們也把這類卡片稱爲霍爾瑞斯卡片,穿孔卡片和穿孔紙帶做爲輸入輸出載體,統治了計算領域整整一個世紀。
在製表機的高效運轉下,1890
年的人口普查只花了 6
年時間。1896
年,霍爾瑞斯成立製表機公司(The Tabulating Machine Company)並不斷改進本身的產品,前後與英國、意大利、德國、俄羅斯、澳大利亞、加拿大、法國、挪威、美國波多黎各、古巴、菲律賓等多個國家和地區合做開展了人口普查。
到 1914
年,製表機公司天天生產的穿孔卡片多達 200
萬張。很少久,一些競爭對手逐漸起家,歷史迎來了繁榮的數據處理時代。它們的產品也再也不侷限於人口普查,逐漸擴展到會計、庫存管理等一些一樣須要跟大數據打交道的領域,這些機器做爲製表機的後裔被統稱爲單元記錄設備(unit record equipment)。
圍繞穿孔卡片的制卡、讀卡、數據處理和卡片分類是它們的標準功能,穿孔機、讀卡器、分類器是它們的標準配置。這些部件的自動化程度愈來愈高,好比手動的讀卡裝置很快被自動讀卡機所取代,讀卡速度從每分鐘 100
張逐步提升至每分鐘 2000
張。隨着識別精度的提升,卡片的孔距也愈來愈小,具備 80~90
列孔位的卡片成爲主流,有些卡片的孔位甚至多達 130
列。
機器的功能也逐漸強大,再也不只是簡單地統計穿孔數目,減法、乘法等運算能力陸續登場。1928
年,哥倫比亞大學的科學家們甚至用單元記錄設備計算月球的運行軌跡,他們在 50
萬張卡片上打了 2000
萬個孔,彰顯着單元記錄設備的無限潛力。
機器的電路實現愈來愈複雜,但同時也愈來愈通用。1890
年所用的那臺製表機的 線路是固定的,遇到新的統計任務,改造起來十分麻煩。
1906
年,霍爾瑞斯便引入了接插線板(plugboard)——一塊佈滿導電孔的板卡,可經過改變導線插腳在板上的位置改變線路邏輯。試想一下,接插線板的內部已經布好了具備各類功能的線路,但它們都處在斷開狀態,各自鏈接着接插線板上的某兩個孔位,像一窩嗷嗷待哺的小鳥長大着嘴巴,外部的導線就像美味的蟲子,當蟲子的頭尾分別與小鳥的上喙和下喙接觸,線路就被導通,這隻小鳥就開始工做了。如此,每次使用就能夠激活不一樣的 「小鳥」,從而完成不一樣的任務。這已是一種可編程性的體現。
1911
年,製表機公司與另外 3
家公司合併成立 CTR 公司 (Computing-Tabulating-Recording Company),製表機公司做爲其子公司繼續運營到 1933
年。
1924
年,CTR 改名爲 國際商業機器公司(International Business Machines Corporation),就是如今大名鼎鼎的 IBM 公司。可見,在現在衆多年輕的 IT 公司中,擁有百年曆史的 IBM 是位當之無愧的前輩,它完整地參與和見證了整個現代計算機的發展史。IBM 保持了製表機公司在單元記錄市場的龍頭地位,到 1955
年,其天天生產的穿孔卡片多達 7250
萬張。
1937
年開始,單元記錄設備逐步電子化,與電子計算機的界線漸漸模糊,並最終爲後者讓路。隨着 1976
年 IBM 一型最核心的單元記錄產品的停產,短暫的單元記錄時代也宣告謝幕,它彷彿是電子計算時代來臨前的預演和鋪墊,許多設計被沿用下來,好比穿孔卡片和接插線板。
有趣的是,即便電子計算機逐漸普及,許多機構因爲用慣了單元記錄設備,遲遲不肯更換,少數機構甚至一直用到了 21
世紀。
編程可以幫助咱們解決一些很是實際的問題,用一種很是酷的方式。
感興趣也能夠擴展閱讀一下: 改變世界的代碼行
在討論「二進制」和「CPU 如何工做」以前,咱們先來討論一下咱們生活中最稀疏日常的 數字,咱們與之頻繁地打交道:一個約定的時間、一件商品的價格、一我的的身高....卻不多有人細細想過,這些數字是如何表達出來的?爲何你理所固然地把 1024
理解爲「一千零二十四」而不是別的含義?
也許你從未想過,在這簡單的記數中,沉澱着人類的大智慧。
早在數字的概念產生以前,人類就學會了使用樹枝、石子、貝殼等天然界隨處可見的小物件表示獵物的、果實的、部落人口的數量。好比在某個角落堆上一堆石子,每打到 1 只獵物,就扔 1 顆石子進去,每吃掉 2 只獵物,就從中取走 2 顆石子。他們並不在乎石子的總數,只是時不時地瞅一眼,心底大體有數。
其實這是一種最樸素的記數方式,數學家稱之爲 一進制記數法(unary numeral system)。咱們把它符號化一下,好比用斜槓 /
來表示:
1
就是 /
;2
就是 //
;4
就是 ////
;好像沒毛病,咱們平時掰手指用的就是這種記數法,但數字一大,場面就要失控了。
爲了解決記錄大數的問題,因而咱們得發明一些其餘符號來表示更大的數值,好比用橫槓 -
表示 10
,用十字 +
表示 100
。那麼:
16
就是 -//////
;32
就是 ---//
;128
就是 +--////////
;漂亮....這種靠符號類型和符號數量表示數字的方法被稱爲 符值相加記數法(sign-value notation),古埃及和古羅馬用的都是它,只不過符號各不相同。
古埃及的記數符號:
1 | 10 | 100 | 1000 | 10000 | 100000 | 1000000 |
---|---|---|---|---|---|---|
1024
在古埃及就寫做:
你會發現,符值相加記數法的一大優勢是,符號的順序能夠任意打亂,數字含義不受影響。我國藏族曾用石子表示 1
、木棍表示 10
、果核表示 100
、蠶豆表示 1000
、瓦片表示 10000
,那麼,當你把 1
顆蠶豆、2
根木棍和 4
顆石子胡亂地攥在手裏,別人依然知道它們是 1024
。
古羅馬的作法略有不一樣,他們對五進制情有獨鍾:
1 | 5 | 10 | 50 | 100 | 500 | 1000 |
---|---|---|---|---|---|---|
I | V | X | L | C | D | M |
這些符號沿用至今,想必你們(至少對前 3
個)都比較熟悉,許多鐘錶仍保留着使用羅馬數字的習慣,1~12
分別表示爲:I
、II
、III
、IV
、V
、VI
、VII
、VIII
、IX
、X
、XI
、XII
。你會發現,羅馬記數法是符值相加記數法的變種,由於它不光「相加」,還「相減」。這種方式就不容許符號亂序了,IV
和 VI
表示的是不一樣的數字。
那羅馬人何苦要使用這種更復雜的記數法呢?無非是爲了讀寫方便。一樣表示 9
,IX
比 VIIII
更簡潔。
其實有一種更好使的方法——用另一些列符號來表示符號的數量。好比用 A
表示 1
個符號,用 B
表示 2
個符號,以此類推,用 I
表示 9
個符號。
如此,上文表示 256
的 ++-----//////
就能夠寫做 B+E-F/
。你必定感受莫名其妙,這種寫法哪裏方便了。其實中文的數字表示就是這種形式,只不過咱們用得太習慣了,以致於沒有發現。
在中文中,個
、十
、百
代替了 /
、-
、+
,而 一
、二
、三
代替了 A
、B
、C
。256
就寫做 二百五十六個
,個
比較累贅,咱們一般把它省略了。
其實像日語、英語用的也一樣是這種記數法,簡潔、優雅。
美中不足的是,這種形式雖便於讀寫,卻不便於計算。中國古人爲算籌和算盤這類經典算具搭建起廣闊的舞臺,卻沒給筆算留出一席之地。想象一下,若是讓你把這些漢字寫在草稿紙上,列個豎式,你的心裏必定很是彆扭。
公元5世紀,印度數學家阿耶波多(Aryabhata 476–550)創立了如今普遍使用的 位值制記數法(positional notation/place-value notation),該記數法使用的主要符號,是同爲印度人發明的阿拉伯數字:0
、1
、2
、3
、4
、5
、6
、7
、8
、9
。
與符值相加記數法類比,位值制中的 1
、2
、3
代替的是 A
、B
、C
,那 /
、-
、+
呢?是 靠阿拉伯數字的位置來表示的。衆所周知,最右位至關於 /
,次右位至關於 -
。靠每一個位置上的數值來表示數字,故名位值制。
嚴謹的數學家用一種多項式高度歸納了位值制記數法的本質,在十進制中,這個多項式是這樣的:
這是一個 n
位十進制數,ai 就是第 i 位上的數值。爲便於直觀理解,舉個 1024
的例子吧:
因爲咱們熟悉了十進制,這樣費心費力的展開可能會讓你以爲可笑,但當咱們把它推廣到其餘進制時,這個多項式的價值就體現了出來。n 位 b 進制數的位值製表示:
1024
用二進制怎麼表示?
所以,1024
的二進制寫做 10000000000
。
除了最廣泛的十進制和計算機中的二進制,常見的還有七進制(如 1
周 7
天)、十二進制(如 1
年 12
個月)、十六進制(如古代 1
斤 16
兩)、六十進制(如六十甲子)等等,只要有意義,任何進制均可覺得你所用。
至此,你對「二進制」或許再也不那麼陌生,它僅僅是數制的一種而已。
可爲何必定是二進制呢?使用人類習慣的十進制很差嗎?
計算機依靠電力工做,這也就意味着須要將數字信號映射到電信號,實現這種映射最簡單的方法是:
二進制在技術上最容易實現。這是由於具備兩種 穩定狀態 的物理器件不少,如門電路的導通與截止、電壓的高與低等,而它們剛好能夠對應表示 「1」 和 「0」 這兩個數碼。假如採用十進制,那麼就要製造具備 10
種 穩定狀態 的物理電路,而這是很是困難的。
爲何使用更復雜的數字系統是一個問題?
假設咱們使用三元(3 位數字)數字系統涉及計算機,若是咱們具備從 0 V
到 5 V
的電壓,那麼咱們能夠進行如下的映射:
看起來合理吧?可是,想象一下,我以 2.5 V
的電壓發送了一個數字。可是因爲電路中的一些噪聲,我在輸出端獲得 2.3 V
的電壓,所以將其視爲 0
。結果是?
有人給我發送了 1
,但我將其視爲 0
。數據丟失但是一個很是嚴重的問題。
使用二進制則可靠得多,因爲電壓的高和低、電流的有和無等都是一種 質的變化,兩種物理狀態穩定、分明,所以,二進制碼傳輸的抗干擾能力強,鑑別信息的可靠性高。
創建數字系統的目的是 僅在某些時間點測試開/關(二進制)值,這使電線(或其餘設備)有時間更換。這就是計算機系統有時鐘的緣由。
時鐘會週期性地進行信號的測量,圖中所示的 T1 和 T2 就是能夠測量信號的時間點。
時鐘利用全部這些時間點來保持同步。更快的時鐘意味着每秒能夠對電線進行更屢次測試,而且整個系統運行得更快。2 GHz
處理器每秒檢查二進制值 20
億次。在這些時間之間,容許值改變並穩定下來。處理器芯片速度越快,每秒能夠測試的次數就越多,每秒能夠作出的決策就越多。
數學推導已經證實,對 N
進制數進行算術求和或求積運算,其運算規則各有 N(N+1)/2
種。如採用十進制,則 N=10
,就有 55
種求和或求積的運算規則;而採用二進制,則 N=2
,僅有 3
種求和或求積的運算規則,以上面提到的加法爲例:
0+0=0,0+1=1 (1+0=1),1+1=10
於是能夠大大簡化運算器等物理器件的設計。
採用二進制後,僅有的兩個符號 「1」
和 「0」
正好能夠與邏輯命題的兩個值 「真」 和 「假」 相對應,可以方便地使用邏輯代數這一有力工具來分析和設計計算機的邏輯電路。
雖然在 1950
年代就造出了更加高效的三元計算機,但在效率和複雜度的取捨上,始終抵不過二進制。二進制仍然在當今世界中長期存在。
上面咱們瞭解到計算機以二進制的形式運行,它們只有兩種狀態:開(1)和關(0),爲了執行二進制計算,咱們須要採用一種特殊的電子元器件,稱爲 「晶體管」。暫時咱們把它理解爲一種開關吧,通電就打開,沒電流經過就關閉。
咱們知道,給電燈通上電,它就會亮:
因而,結合上開關,咱們就能搭建出最基礎的 與門 和 或門。
該電路的邏輯是:只有當 A 和 B 同時開啓時,LED 燈纔會亮,也就是認爲輸出 1,咱們能夠利用電信號來簡單模擬一下:
A | B | Y |
---|---|---|
0 | 0 | 0 |
1 | 0 | 0 |
0 | 1 | 0 |
1 | 1 | 1 |
該電路的邏輯是:當 A 或者 B 開啓時,LED 燈就會亮,也就是認爲輸出 1,咱們能夠利用電信號來簡單模擬一下:
A | B | Y |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 1 |
相似地,咱們能夠藉助更多的電子元器件來創造出基礎的 7
種邏輯門電路:
這裏須要特別提一下 異或門,咱們須要先知道有一種電子元器件能夠利用電氣特性對 輸入取反,也就是說輸入 1
則輸出 0
,輸入 0
則輸出 1
,那麼咱們就能夠 簡單模擬 出異或門邏輯電路(實際會更復雜些,這裏僅展現出異或的意思):
A'
和 B'
分別表示 A
和 B
開關的反值,從圖中咱們很容易知道只有當 A
、B
只存在一個輸入 1
時,整個電路纔會輸出 1
。
OK,上面咱們瞭解到咱們可以利用 "開關" 來模擬邏輯的運算,咱們接下來試着還原一個簡單的加法運算器是如何實現的:
僅需兩個門,就能夠完成基本的二進制加法運算。上圖是利用 logic.ly
建立的半加法器,A
、B
至關於使咱們計算的兩個數,最後一塊至關因而咱們的數顯芯片,它的功能是根據輸入顯示數字,從上到下的引腳(也就是圖中輸入的地方,一般咱們這樣稱呼)分別對應了 20=1、21=2、22=4、23=8 的輸入,沒有任何輸入時顯示爲 0
,若是 引腳 1
(對應 20=1)像上圖同樣有輸入,則顯示 0 + 1 = 1
。
咱們來理解一下上方的電路:
引腳 1
,顯示 數字 1
(相似於 1 + 0 和 0 + 1
);引腳 2
,顯示 數字 2
(相似於 1 + 1
);數字 0
(相似於 0 + 0
);所以,若是兩個都打開,則 XOR 保持關閉,而且 AND 門打開,得出正確的答案爲 2
:
但這只是最基礎的半加法運算器,不是太有用,由於它只能解決最簡單的數學問題之一。但若是咱們把它們兩個與另外一個輸入鏈接,就會獲得一個完整的加法器:
仔細思考幾遍,你就會得知這個三個輸入的加法器已經能夠計算 3
個二進制數字的加法運算了,咱們如法炮製,能夠經過鏈接更多的"進位"來使這個加法器可以運算更多的數,這固然也意味着這個計算鏈條更長。
大多數其餘數學運算均可以加法完成。乘法只是重複加法,減法能夠經過一些奇特的位反轉來完成,而除法只是重複減法。而且,儘管全部現代計算機都具備基於硬件的解決方案以加快更復雜的操做,但從技術上講,您可使用完整的加法器來完成所有操做。
編碼伴隨探索和學習新知的過程,若是願意,咱們能從中獲取不少相似於解出一道數學題的樂趣。
咱們已經瞭解了 二進制和 CPU 的基本原理,知道了程序運行時,CPU 每秒數以億次、十億次、百億次地震盪着時鐘,同步執行着微小的 「電子操做」,例如:從內存讀取一個字節的數據到 CPU 又或者判斷字節中的某一位是 0
仍是 1
。
CPU 自己有一組 規定好的 能夠執行的 「基本動做」(被稱爲 機器指令):
這幾乎就是 CPU 工做的所有了。 這些動做雖然每次只能執行一次,可是每秒能夠執行數十億次,這個數量級的「小操做」累加成爲一個大的「有用的操做」。
處理器所作的一切都是基於這些微小的操做!幸運的是,咱們已經再也不須要了解這些操做的詳細信息就能夠編寫和使用各種程序。諸如 Java 這一類的 「高級語言」 的 目的 就是 將這些微小的電子操做組織成由人類可讀的「程序語言」表示的大型有用單元。
儘管機器語言有一些反人類,但至少咱們能夠用它來來編寫代碼了,如:
00000001 00000010 00000001 00000100 00000100 00000000
彷佛看着這一段兒代碼有點迷糊,而且 可讀性太差了。
如此你就會感知到 上個世紀 的程序員使用 打孔卡片:
使用 紙帶:
甚至是 直接插拔線路 or 按下開關:
是一件多麼硬核的事情...
PU 的指令都是 二進制 的,這顯然對於人類來講是 不可讀 的。爲了解決二進制指令的可讀性問題,工程師將那些指令寫成了 八進制。二進制轉八進制是垂手可得的,可是八進制的可讀性也不行。
很天然地,最後仍是用文字表達,加法指令寫成 ADD
。內存地址也再也不直接引用,而是 用標籤 表示。
這樣的話,就多出一個步驟,要把這些文字指令翻譯成二進制,這個步驟就稱爲 assembling
,完成這個步驟的程序就叫作 assembler
。它處理的文本,天然就叫作 aseembly code
。標準化之後,稱爲 assembly language
,縮寫爲 asm
,中文譯爲 彙編語言。
舉個簡單的例子,咱們須要計算:
(1 + 4) * 2 + 3
咱們按照 「後綴表示法」 進行一下轉換:
1,4,+,2,*,3,+
咱們日常使用的方法是 「中綴表示法」,也就是把計算符號放中間,例如 1 + 3
,後綴則是把符號放最後,例如 1, 3, +
。
這樣作的好處是沒有先乘除後加減的影響,也沒有括號,直接運算就好了。(例如 1, 3, +
,先把 1
和 3
保存起來碰到 +
知道是加法則直接相加)
OK,咱們從頭開始使用匯編語言來編寫一下程序,首先第一步:把 1
保存起來(放入寄存器):
MOV 1
以後是 4, +
,那就直接加一下:
ADD 4
而後是 2, *
,那就直接乘一下(SHL
是向左移動一位的意思,二進制中左移一個單位就至關於乘以 2
,例如 01
表示 1
,而 10
則表示 2
):
SHL 0
最後是 3, +
,再加一下:
ADD 3
完整程序以下:
MOV 1 ADD 4 SHL 0 ADD 3
這彷佛看起來比 00001111
這樣的二進制要好上太多了!程序員們感動到落淚:
擺脫了 二進制,咱們有了更可讀的 彙編語言,但仍然十分繁瑣和複雜,每一條彙編指令表明一個基本操做,例如:「從內存 x 位置獲取一個數字並放入寄存器 A」、「將寄存器 A 中的數字添加到寄存器 B 的數字上」。這樣的編程風格既費時又容易出錯,而且一旦出錯還很難發現。
例如,咱們來看一看 「1969 年阿波羅 11號登月計劃」 用來 防止登月艙計算機耗盡自身資源 的 BAILOUT 代碼:
POODOO INHINT CA Q TS ALMCADR TC BANKCALL CADR VAC5STOR # STORE ERASABLES FOR DEBUGGING PURPOSES. INDEX ALMCADR CAF 0 ABORT2 TC BORTENT OCT77770 OCT 77770 # DONT MOVE CA V37FLBIT # IS AVERAGE G ON MASK FLAGWRD7 CCS A TC WHIMPER -1 # YES. DONT DO POODOO. DO BAILOUT. TC DOWNFLAG ADRES STATEFLG TC DOWNFLAG ADRES REINTFLG TC DOWNFLAG ADRES NODOFLAG TC BANKCALL CADR MR.KLEAN TC WHIMPER
彷佛不太容易讀的樣子...
阿波羅登月計劃的源代碼在 Github 上已經公開,有興趣的能夠去下方連接膜拜一下(能夠去感覺一下當時程序員的工程能力):
另外附一下當時代碼的設計負責人 Margaret Heafield Hamilton(女程序員)和完成的堆起來跟人同樣高的代碼量:
當 John Backus 在 1950
年以一名科學程序員的身份加入 IBM 時,已經可使用諸如 ADD
之類的助記詞代替數字代碼來編寫程序,也就是咱們的彙編語言。這使編程變得容易一些,可是即便是一個簡單的程序也須要數十次操做,而且仍然很難找到錯誤。
巴克斯認爲,應該有可能建立一種編程語言,使一系列計算能夠用相似於數學符號的形式來表達。而後,使用特定的翻譯程序(以今天的術語來講是編譯器)能夠將其轉換爲計算機能夠理解的數字代碼。
Backus 在 1953
年向他的經理提出了這個想法。他獲得了預算,並被鼓勵僱用一個小團隊來測試該想法的可行性。三年後,該團隊發佈了一本手冊,其中描述了 IBM Mathematical Formula Translating System(簡稱 FORTRAN)。不久以後, IBM 向 IBM 704 的用戶提供了第一個 FORTRAN 編譯器。
Backus 和他的團隊創造了世界上第一種高級編程語言。科學家和工程師將再也不須要將其程序編寫爲數字代碼或冗長的助記符。
下面演示計算並輸出 8 * 6
的代碼實例:
program VF0944 implicit none integer a, b, c a= 8 b= 6 c= a*b print *, 'Hello World, a, b, c= ', a, b, c end program VF0944
對比彙編代碼,是否是看上去要清晰(人類可讀)多了呢?
FORTRAN 的問世在計算機史上具備劃時代的意義,它使計算機語言從原始的低級彙編語言走出來,進入了更高的境界,使得 計算機語言再也不是計算機專家的專利,使廣大的工程技術人員有了進行計算機編程的手段。
由此計算機更快地深刻到了社會之中,它在工業部門中初露頭角,更是在火箭、導彈、人造地球衛星的設計中大顯身手,所以有人稱 FORTRAN 語言使計算機的工業應用成了可能,是推進第二次世界大戰之後西方工業經濟復甦和進入第二次工業革命的無形力量,是 "看不見的蒸汽機"。
計算機先驅們已經爲咱們架設好了計算機的世界,站在先驅巨人們的肩膀,咱們現在很容易也能夠看得更高和更遠。
編碼的樂趣有不少,把本身的想法動手實踐就是其中一個。
例如網友玩兒遊戲活動須要不停點鼠標,因而寫了一個鼠標連點器:
例如給本身心愛的妹子寫一個戀愛記念網站:
例如給 FlappyBird 加一個強化學習算法讓它本身學習如何飛行:(圖示已經能本身飛 4527
步了)
例如網友本身寫的文言文語言:(使用文言文寫代碼)
// HelloWorld 程序演示 吾有一數。曰三。名之曰「甲」。 為是「甲」遍。 吾有一言。曰「「問天地好在。」」。書之。 云云。
運行輸出:
問天地好在。 問天地好在。 問天地好在。
咱們能夠動手經過編程把咱們的不少想法付諸於實現 (前提是不斷探索和學習),並在迎接挑戰和最終實現的過程當中得到無限的樂趣。
整體而言,IT 是使人興奮的。
素有「軟件吞噬世界」的說法,咱們也正生活在計算機當道的世界。
而且編程並非每一個人都具有的技能,藉助技術,一切皆有可能,而且如今互聯網時代比以往都更有機會學習和建立「本身的世界」。
- 本文已收錄至個人 Github 程序員成長系列 【More Than Java】,學習,不止 Code,歡迎 star:https://github.com/wmyskxz/MoreThanJava
- 我的公衆號 :wmyskxz,我的獨立域名博客:wmyskxz.com,堅持原創輸出,下方掃碼關注,2020,與您共同成長!
很是感謝各位人才能 看到這裏,若是以爲本篇文章寫得不錯,以爲 「我沒有三顆心臟」有點東西 的話,求點贊,求關注,求分享,求留言!
創做不易,各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!