彭民德:《電子計算60年》(4) 從學習蘇聯電子管計算機開始

彭民德發表於2016-06-03

無論電腦科學理論的提出,還是計算機體系結構的完善,以及像圖靈、馮•諾依曼這些計算機界的開山鼻祖都在西方,世界上第一臺電子計算機ENIAC誕生於美國,第一臺儲存程式的電子計算機出自英國,學習第一代計算機本應以美歐典型機器為藍本。但是當時世界處於兩大陣營冷戰時期,我們無法接觸西方的機器和資料。學習計算機只能靠學習蘇聯老大哥的機器。蘇聯的計算機事業比西方晚一些,從1948年起步,但是還不錯,到50年代中期,有了M-2、M-3、箭牌、БэСМ等機型。

當時中蘇友好,除了北大、中科院計算所等選派技術人員赴蘇考察學習,蘇聯還派計算機專家來幫助我們起步。斯梅格列夫斯基就是來華專家之一,1957年秋天起他在中科院計算所主講了《機器數學》課程。中科院計算所的技術人員曾經根據主講專家的講稿整理出版了《程式設計基礎》一書(科學出版社,1958年10月)。本書簡介寫道:

斯梅格列夫斯基上的這門《機器數學》課程內容有程式設計基礎、程式自動化、程式檢查及其自動化、機器上的工作組織問題、試驗機器的檢驗程式等課題。書中系統地介紹了蘇聯在機器數學工作方面的先進經驗。 作者在其引言中,說本書目的是“介紹蘇聯發展的程式設計的運算元法,詳細介紹M-3機器及其程式設計”。蘇聯專家這本書沒有引用一份西方的資料,也沒有參考文獻。

於是從赴蘇學習開始,從蘇聯專家來華講學開始,從中科院計算所、北大等開始,我國有了最早一批學習蘇聯電子計算機的人。機器也陸續從蘇聯引進。斯梅格列夫斯基在他的書“引言”中寫道“最近計算所就要有一架M-3了”。這裡講的計算所,是中科院計算技術研究所,所提到的這一架M-3就是蘇聯的計算機。它是蘇聯最早的計算機,也是我國最早的電子數值計算機,這是1957年的事。稍後上海也有了一臺蘇聯的浮點型計算機БЕСМ,復旦大學編寫的程式設計教材就是根據БЕСМ機寫的。

M-3機以磁鼓作為儲存器,平均每秒只作30次定點運算。容量也小,只有2048個單元。用現在的話說,只有2K個單元(當時不用K這個儲存單位)。也就是說,程式加資料不能超過2K個單元,今天看來小得很。每個單元31個二進位制位,可以存放一條指令或者一個資料。輸入速度每分鐘30個數字,電傳打字機穿孔列印輸出也是每分鐘30個數字。

M-3機的運算速度遠不及世界上第一臺電子數字計算機ENIAC,美國的這款機器,速度達每秒5000次,這反映了當時蘇聯的計算機水平跟西方有相當大的差距。M-3機也是我們直接程式設計使用的第一代計算機的典型代表。

浮點型的蘇聯箭牌機記憶體也是2048個單元,但單元長度有43個二進位制位,這意味著這款機器的運算精度比M-3機要高一些。而後來的БэСМ機運算速度可達8000-10000次/S。

定點機與浮點機的概念來自於計算機中對資料的不同表示方法。比如十進位制數432.56,在日常生活中,可以寫成103×0.43256,也可以寫成10×43.256,104×0.043256等其它形式。在計算機中,數通常被寫成±10p×α,其中0≤α<1,α=a1a2a3…an。這裡的整數p決定小數點位置,稱為數的階。它可正可負,亦可為0。要求階碼p為常數的機器稱為定點機,亦即其小數點位置是固定的。階碼p可變的機器稱為浮點機。可見浮點機比定點機表示數要靈活一些,可以表示更大範圍的數。稱ai(i=1,2,3,…,9)為尾數。如果能夠保證a1≠0,即0.5≤α<1, 尾數將有最多的位數,表示的數精度最高。達到這種要求的數稱為規格化的數。我們對M-3進行程式設計時,常常要求設定比例因子,將數規格化,這又加大了程式設計難度。

當時只有基於M-3計算機廠家提供的機器指令用來程式設計,每條指令中無論資料還是操作碼,全部都是0與1的串。這是計算機運算器和控制器能夠識別並執行的唯一的程式碼。機器指令屬於硬體範疇,不同機器的指令系統也不同。後來有了軟體後,有時為了強調它們屬於硬體範疇,以便跟高階語言的語句相區別,也叫機器硬指令。每一條指令的功能單一,比如啟動或停止機器,向某個記憶體單元置一個數,把一片連續的單元清零,向某個埠地址賦一個數值,從某個埠地址取一個值,等等。

指令序列構成程式。程式功能就可以很豐富了,因為它是人的智慧的反映,可以把一片資料排序,選出其中的最大最小值,甚至可以求解微分方程式。

計算機的最基本特點就是能夠儲存程式,並且可以逐條指令自動執行。每條指令的執行過程是:把該指令從記憶體送到控制器;控制器分析指令,發出從記憶體哪個單元取數和進行哪種基本操作的訊號;運算器接受訊號,對該數進行運算;控制器發出訊號,把運算結果送到應送達的單元;機器準備轉入執行下一條指令。機器能夠執行的指令種類條數越多,或者說廠家提供的指令集越大,程式設計師就能夠編寫功能更強的程式。

M-3機每條指令都由操作碼和運算元組成。操作碼θ佔8個二進位制位。運算元有兩個,分別為第一運算元A1和第二運算元A2。A1和A2表示記憶體地址,各佔12個二進位制位。在具體運用把每條指令寫到程式中的時候,必須明確指定操作碼和運算元,成為一條可以執行的指令。

θ    A1    A2

每條指令的三個域共32個二進位制位,與M-3機記憶體單元長度一致。所有的操作碼和運算元都是數字。規定在程式中用8進位制數形式表示每條指令,每個8進位制數佔3個二進位制位。比如指令

00     0001     0002   

表示θ為00,其操作是做加法。該指令的功能是,把0001單元的內容與0002單元內容相加,將結果送往暫存器B,而後回存到0002單元。這條指令送到記憶體就是00000000000000000001000000000010

指令從功能上分為:算術運算、邏輯運算、程式碼傳送、控制指令、停機五種。標準子程式也只有五種,即數制轉換、指數函式、對數函式以及三角函式的sin(x)和cos(x)。指令地址要自己分配。只有數字型別資料,程式只能做數字計算。

計算機有了指令集,只表示計算機有了潛在的計算能力。計算機只會執行指令,完了再依照控制暫存器所指的下一條指令地址,從記憶體取下一條指令執行。單條指令的功能很單一,要計算機做事就必須程式設計序,組織一個指令序列。指令集是廠家提供給程式設計人員,用來程式設計的指令格式規範,並非直接可執行的指令。寫到程式中的指令是指令集中指令的具體化運用。具體指令序列構成程式。如何遵從指令的格式,從指令集中選用適當的指令,順序地逐條地完成每條指令的設計,構成能夠實現某種功能的程式,就要組織資料,規劃記憶體,設計演算法。這強烈地依賴於人的智慧,對於我們學習計算機那是一個跨越,也是必須掌握的基本功,是每個人都繞不開的困難工作。

由指令序列構成的每個程式,其中全部都是0與1,在紙面上規定用8進位制書寫,因此全部是數字0到7。無論是操作碼還是地址運算元都無一例外。即便是個十進位制常數20,也必須寫成八進位制024,並且給它分配儲存單元。再用傳送指令把它從穿孔紙帶上,預存到指定的儲存單元中,以後通過地址操作從該單元取用。滿篇的純數字序列,說它們是天書也真不為過。在紙上編制程式時不得不在指令旁邊自己做些註解,作為對自己的提醒。

編制程式前首先要畫流程圖,而後規劃記憶體佈局。每條指令和每個資料在記憶體佈局,都必須由程式設計師來細心劃分。程式設計技術很難掌握。特別是因為M-3是定點機,所有初始資料、中間結果以及最後結果的絕對值都必須小於1,大於0.5,程式設計師常常要設定比例因子,強制將數值範圍控制起來,稍有不慎就會造成機器溢位。

舉一個用M-3機器指令程式設計的例子,試編寫求表示式

f = ((x2 + y2 –z2) sin x)/( x2 + y2)

的值的計算程式,其中sin x用近似式x– x2/6表示(–1 < x, y, z < 1)。為使數值不溢位,先要把計算式改寫成

f = ((x2 /2 + y2 /2 – z2 /2) sin x)/( x2 /2 + y2 /2)

接著程式設計師要給指令和資料分配地址,對記憶體做出規劃。假定把初始資料x、y、z分別存放在0024~0026號(約定用八進位制書寫)單元中,1/2, –1/6分別放在0027、0030單元,程式則從0005號單元開始,至0023單元。每條指令除了操作碼可能還有運算元A1或運算元A2, A1,A2一般都表示地址。程式如下:

指令地址 操作碼θ     A1         A2         說明
0005     +13      0025      0025   y2 →暫存器B
0006     +23      0027      0001   y2 /2 →0001
0007     +13      0026      0026   x2 →B
0010     +23      0027      0002   z2 /2 →0002
0011     +13      0024      0024   x2 →B
0012     +33      0027             x2/2 →B
0013     +20      0001      0001   x2 /2 + y2 /2→B→0001
0014     +31      0002             x2 /2 + y2 /2 –z2 /2→B
0015     +22      0001      0002   ((x2 /2 + y2 /2 – z2 /2) sin x)/( x2 /2 + y2 /2) →B→0001
0016     +13      0024      0024   x 2 →B
0017     +33      0030             x2/6 →B
0020     +33      0024             –x2/6 →B
0021     +30      0024             x– x2/6 →B
0022     +63      0002      0002   f →B →0002→∏
0023     +77                       Ω(停機)

上述程式中每一行共有5個域,在紙面上人為地用空格分開,便於閱讀。最左邊一列指令地址就是由程式設計師安排的記憶體地址,是右邊跟隨指令“操作碼θ 運算元A1 運算元A2”要送往的地方,它不屬於程式內容,不輸入。最右邊的說明是寫給人看的,也不能輸入。中間3列的指令序列就是程式,機器可以直接執行的程式。除了操作碼可能有加減號,全部是8進位制數字。除去地址域、說明部分以及印刷時加的空格,輸入給機器的八進位制程式程式碼部分如下:

+1300250025
+2300270001
+1300260026
+2300270002
+1300240024
+330027
+2000010001
+310002
+2200010002
+1300240024
+330030
+330024
+300024
+6300020002
+77        

為了便於讀者閱讀,上述程式在這裡印刷時保留了換行符,以區別各條指令。這個換行符不輸入。而且到了機器內部,上述程式將被全部轉化為2進位制程式碼,被依序逐條地存放在確定的記憶體單元中,同時也就沒有換行一說了。這種程式沒有可讀性,只有計算機的控制器和運算器能夠讀懂並執行。這在今天只要把待計算的式子用表示式賦值,三兩條高階語言的語句,便可解決問題,當時要這麼麻煩, 寫了15條機器指令的一段程式。

上面這段程式,也很好地反映了計算機內部,做數字處理的本質特徵,它表明,在計算機內部,除了數字0與1,什麼都沒有。但它的簡單背後,奧妙無窮。

第一,0與1可以表示數,而且比十進位制表示有更高的精度,計算也更簡單。當然用0和1表示數是近似的,受到機器字長的限制。不但無法準確地表示無理數,連有理數甚至常數都無法準確地表示。就連對0的表示都不一樣,實際的零是“什麼都沒有”,在通電的計算機上,“什麼都沒有”怎麼能夠準確表示呢?因而還有與數學上不同的機器0一說。可見計算機的計算,只是對現實世界的近似。但是這種近似已經足夠了。

第二,0與1可以表示記憶體地址。比如當它們出現在指令的地址運算元域時就是地址,指出參與操作的資料所處的位置,就像住戶的門牌號。計算時可以準確地到指定位置找到確定的數。

第三,0與1可以表示指令施行的某項特定操作。在M-3機器上用8個二進位制位作為操作碼θ,可以區分28=512種不同指令。後來的機器雖然設定了更多指令,但用8位也就夠了。

第四,0與1可以表示邏輯,比如0假1真。記憶體中的程式通常是順序執行的,但是可以依據設定的種種條件轉移,比如“為0轉左”,“為1轉右”;可以用來判斷某個計算的設定精度是否滿足,因而迴圈次數是否夠了。這很重要,藉助它,可以實現程式的轉向、重複、退出等邏輯的操作。使得程式在執行中可以自主地判斷下一步該怎麼做,實現計算的自動化。還有一套基於布林代數的邏輯運算規則,正確使用了邏輯運算的程式,可以使計算機作出快速判斷,這從後來才有的棋類程式可以明顯地看出,計算機下棋比人更快,原因就在於此。

這個階段的0與1還僅僅用於做數值計算。以後逐步發展,可以用0與1描述字元和文字、圖形影像、語音,特別是伴隨計算機之間通訊的發展,計算機的本事就越來越大了。電子計算機的自主計算能力,決定了它不僅僅可以替代人類既往的計算,隨著其速度與容量的提高,演算法的改進,一定可以不斷地創造新的計算奇蹟。

這個階段的程式中,每條指令都是機器能夠直接識別的。程式的結構,指令的格式都有規範,地址運算元不能越界,資料不能溢位,後來也把這個階段的程式設計叫做機器語言程式設計。

機器語言程式設計可以說是令人望而生畏的,因為編制的整個程式中,除了數字,什麼都沒有,難以看懂。既難以書寫又難以發現和改正錯誤。但也從此看到了希望。比如機器指令級程式設計雖然沒有以後高階語言的迴圈控制結構,但是費點勁還是可以實現迴圈設計。假如要計算S=1+2+3+…+100這樣的操作,人們用手計算時,必須一個一個數相加,算它99次。只有在特殊情況下才可以像高斯所曾經做過的那樣有簡便方法。計算時還得用一些紙張。寫計算機程式則只要指定一個單元為求和單元S,利用計算機的累加器B,分別給S和B置初值0和1。程式只要讓B單元和S單元的內容相加,結果放回S,再讓B的值增1,再加,用轉向語句不斷迴圈。直到B的值超過100,滿足這個特定條件,停止迴圈。S中的值將由0變成0+1的1, 1+2的3, 3+3的6等等。當自動做了99次加法迴圈結束時,S中就是要求的結果5050。它利用指令去重複執行增值、累加等單一的工作,而且都是對記憶體單元進行,無需紙和筆。迴圈次數越多越顯示出其優點,因為無論相加多少次,程式都一樣,只要適當控制程式的迴圈次數就行了。有了這麼一個小的迴圈程式幫忙,個個都會成為高斯,很快就能夠得到正確答案。

開始的計算機只是沒有軟體支援的裸機,像個笨拙的、智力未開發的孩子,只會執行機器指令,使用起來太專業太費勁,但它能儲存程式和資料並以電子速度自動執行程式,執行速度很快,原始資料和加工結果又能儲存,程式可以重複執行,中間無需人去幹預,計算機可以依照程式設計人員的邏輯,自主地執行程式,直至算出結果。中間還省去了紙和筆。這是計算機生命力之所在,也是計算領域革命性之所在。雖然當時程式設計很費勁,但它一定是用於科學計算無與倫比的新工具。

怎樣看待蘇聯的計算機水平?因衛國戰爭的需要,蘇聯經濟長期強調重工業和軍事工業,它的電子工業相對滯後一些,無論計算機產品還是計算技術理論,都沒有特別突出的內容,可以在世界計算機的發展歷史中大書特書。不過畢竟蘇聯的工業基礎雄厚,其電子計算事業雖然晚於西方若干年起步,依然自主地發展起來了,併成功地運用於工業和國防。

我國的電子計算事業起步於蘇聯的幫助。在上個世紀五、六十年代,作為鐵幕這邊無法接觸西方計算機,又尚處在一窮二白狀態的人來說,能夠接觸蘇聯的計算機已經很幸運了。而且就學習而言,基於馮•諾依曼結構的計算機原理, 基於機器語言的程式設計方法,都是一樣的。早期計算機知識的學習,機器指令的運用,演算法設計,流程框圖繪製,記憶體單元的開闢利用,迴圈、迭代技術,資料精度控制,基本的知識以後長期有用。從此我們進入了與此前基於紙上表格式,在課桌上的手工計算不同的計算階段。學習蘇聯早期計算機還提供了以後學習西方新機器的一種對比,讓我們對計算機發展的整個過程有一個更完整、更親切的認識。歷史地看,我們不能忘了蘇聯老大哥的幫助。

但是後來的微機時代,據說因為蘇聯害怕普及帶來的難以控制情報的負面效應,沒有推動計算機的普及和發展,又拉開了與西方的距離。從1984年一則瑞典人的報導可以看到這個趨勢。“一位西方專家評論道:蘇聯人早在25年前就已經懂得計算機技術的意義”。“在計算機發展初期,鑑於蘇聯執行了具有遠見措施的經濟政策,沒有任何一個國家在較好地和有效地利用這一新技術方面趕得上蘇聯。”“現在,計算機已經小型化了,易攜帶,並且不再那麼昂貴了,因此對蘇聯有關國家控制情報的基本原則是一種挑戰和威脅”。“‘人民計算機’的出現,已經給蘇聯的領導者們造成了一個很難解決的問題:老百姓在藉助於自己的小型計算機突然有了可以獲得大量情報的途徑之後,將怎樣控制他們以及怎樣才能發現他們之間相互串通呢?”“西方專家們估計,蘇聯現在使用的計算機最多隻有5萬臺,其中大部分(依然只)用於國防和國防工業。”“現在,他們在計算機的實際利用方面落後於西方很多年。”“蘇聯計算機領域落後一大截子,自然要影響到該國整個工業的發展。”(見1984年8月2日《參考訊息》報導,標題是:“瑞典報紙說 蘇聯在利用計算機方面落後西方很多年 計算機領域的落後影響到該國整個工業的發展”)。再過幾年,因經濟萎縮,人民不滿,導致蘇聯解體。這一教訓說明,計算機事業是關乎國家經濟發展,甚至是國家存亡的大事。應該讓老百姓從計算事業發展中,獲取和共享更多電子資訊,從計算技術進步中得到實惠。

中國人學習了蘇聯早期的計算機技術,使自己能夠在一窮二白基礎上迅速起步。又吸取了後來蘇聯的教訓,大力促進計算機的普及,讓老百姓儘可能從中受益。2016年4月19日,習近平主席在網路安全和資訊化工作座談會上的講話就指出:“網信事業要發展,必須貫徹以人民為中心的發展思想。這是黨的十八屆五中全會提出的一個重要觀點。要適應人民期待和需求,加快資訊化服務普及,降低應用成本,為老百姓提供用得上、用得起、用得好的資訊服務,讓億萬人民在共享網際網路發展成果上有更多獲得感。”

(與本文相關的更多內容可參看 彭民德《電子計算60年》第1章 電子計算新開紀元 電子工業出版社)

相關文章