提到方程,用計算機解方程這個話題是一定會涉及的。我們在前面曾提到過計算機可以用來下棋,當然它還有别的“本事”,比如把一種語言翻譯成另外一種,或者演奏樂器,等等。
我們在這裡并不打算對下棋或者進行語言翻譯等過于複雜的計算機程序進行研究,我們想要分析的隻不過是兩個極簡單的程序,但在這之前,還是要先來簡單地談談計算機的構造。
我們在第一章曾提到過的,能用一秒鐘的時間進行成千上萬次運算的裝置,是計算機中負責進行計算的部分,它叫作“運算器”。事實上計算機中還包括控制器和存儲器(記憶裝置),控制器負責整體調控計算機的工作,存儲器的作用是存放數據和預定信号。除此而外,計算機中還有專門用于輸入新數據和輸出計算結果的裝置,打印機會幫助計算機将這些計算結果以十進制的形式打印在專門的卡片上。
就像你所知道的那樣,我們可以用唱片或錄音帶錄下人的聲音,然後用機器反複播放。但這兩種錄音方式也有不同,用唱片錄音是一次性的,一張唱片隻能錄一次,而用錄音帶就不一樣了。錄音機在錄制聲音時,是借助一種特殊膠帶的磁性作用來進行的,錄在錄音帶上的聲音,不僅可以反複播放,還可以把錄過的内容“抹掉”再錄新的。每條磁帶都能反複使用,想要“抹掉”舊内容,隻要直接錄上新内容就可以了。
計算機的記憶裝置與上述原理相同。計算機借助電信号、磁信号或機械信号,将數和預定的信号錄到專門的磁鼓、磁帶或其他裝置上,這些數與信号可以随時“讀取”,或随時“抹掉”後重新錄入。在記憶或讀取這些數與信号時,計算機所用的時間隻不過是百萬分之幾秒而已。
存儲器内包含着幾千個單元,其中的每個單元内又有磁性元件等幾十個存貯原件。我們假定二進制的存貯方式為:用數字1表示1個被磁化了的原件,用數字0表示沒有被磁化的元件。例如存儲器内的每個單元裡含有的元件數是25個(即有25個二進制位數),其中第1個元件用來表示數的符号(+或-),第2~15個用來存貯數的整數部分,其餘的10個記錄小數部分。圖11中顯示的是存儲器中的兩個單元,每個單元裡都有25個數位,“+”号表示被磁化的元件,“-”号表示沒有被磁化的元件。我們首先來觀察第1個單元(虛線的作用是将表示符号的數位與其他數位區分開,逗号的作用是将整數與小數部分區分開),這個單元計入的數是二進制的“+1011.01”,也就是十進制的“11.25”。
圖11 存儲器中的單元
存儲器不僅可以用來存貯數,它也可以用來存貯指令,我們所說的“程序”就由指令組成。現在我為你介紹所謂的三地址的計算機指令:為了記入指令,要将存儲器的單元分成4段,圖11中的第二個單元就被虛線分成了4段,第幾段就表示第幾道程序,每道程序都以數(編碼)的形式被記入存貯單元裡。比如:
加——操作Ⅰ
減——操作Ⅱ
乘——操作Ⅲ
……
指令是如何被完成的呢?存貯單元的第1段是操作碼;第2、第3段是存貯單元的編号(地址碼),為了完成這一程序,應從這兩段中抽取數字,第4段是用來存放所得結果的貯存單元的編号(地址碼)。比如,圖11中第2個單元所計入的數是二進制的“11、11、111、1011”,也就是十進制的“3、3、7、11”,它們代表的指令是:使用第3和第7存貯單元的數字完成第Ⅲ道程序(即乘法程序),将結果存入第11存貯單元。
接下來我們不需要像圖11中所顯示的那樣,将預先設定好的符号記錄下來,而是要直接用十進制的形式把數和命令記錄下來。比如圖11中的第2單元,我們隻需記錄:乘3711。
現在我們可以對兩個最簡單的程序進行分析了。首先是第一個:
這個程序的5個存貯單元記錄下了計算機上述指令進行工作的過程。
首先指令1:要求計算機把第4單元和第5單元的數相加,将結果存入第4單元(取代第4單元的原存貯數據)。計算機在第4單元記入的數是0+1=1,完成這條指令後,第4、第5單元所存貯的數應該是:
(4)1
(5)1
再來看指令2:要求計算機把第4單元的數與它自身相乘(即算出它的平方),将結果12記到卡片上,箭頭的意思是将結果輸出。
接下來是指令3:要求計算機将操作轉移到第1單元。也就是說,要從指令1開始依次重複執行各條指令。于是計算機開始重複執行指令1。
指令1:把第4單元和第5單元的數相加,将結果存入第4單元,現在第4單元裡的數據就變成了1+1=2:
(4)2
(5)1
指令2:把第4單元的數與它自身相乘,将結果22寫到卡片上。
指令3:将操作轉移到第1單元,也就是再次從指令1開始重複。
指令1:将2+1=3存入第4單元:
(4)3
(5)1
指令2:将3的平方32寫到卡片上。
指令3:将操作轉移到第1存貯單元。
……
現在我們已經弄清楚了計算機的工作程序:按順序計算整數的平方,并将結果寫到卡片上。在這個過程中,不需要你親自去用手敲出每個數,計算機會自己按順序把整數選出來并且逐一計算出它們的平方。隻用幾秒鐘的時間,甚至是在不到1秒鐘的時間内,計算機就可以算出從1到10000的所有整數的平方。
不過,在實際的操作中,讓計算機計算整數平方的程序比我們所寫的這個程序可要複雜多了,而這個“複雜”的部分首先就出現在指令2。要知道,将結果寫在卡片上所用的時間要比完成一道程序多好多倍,所以計算結果出現以後并不能及時地被記入卡片,而是要先被“寄存”在存儲器中的“空”單元裡,然後再被“慢條斯理”地寫在卡片上。具體的方法是這樣的:第一個結果寄存進第一個空單元,第二個結果寄存進第二個空單元,第三個結果寄存進第三個空單元……而我們所舉的例子裡所寫的程序就沒有詳細到這個地步,關于這個内容提也沒提。
除此而外,我們還有一個内容沒有提到,那就是計算機并不能這樣持續不停地進行平方運算,原因在于存儲器中的存儲單元數量有限。也許你會想,既然我們隻想要它計算從1到10000的整數的平方,那麼等它算完10000的平方立刻把計算機關掉就好了。但你怎麼會知道什麼時候恰好算到了10000呢?計算機每秒鐘能進行幾千次運算,我們根本不可能及時地發現它計算到了我們想要的數,并及時打斷它。怎麼辦呢?很簡單,在編寫程序時就為它設計一套特殊的指令,使它在一定的時候自動關機。比如編寫這個程序時,我們就可以加入讓機器計算完1到10000的所有整數平方後自動停機的指令。
說好了隻分析簡單的程序,因此我們就不再涉及更複雜的指令了。計算從1到10000全部整數平方數的完整程序應該是這樣的:
指令1、2與前面分析的簡單程序區别不大,完成這兩條指令,第8、9、10單元的數據變為:
(8)1
(9)1
(10)12
指令3:求計算出第2和第6單元的數據之和,再将結果存入第2單元。第2單元發生如下變化:
這裡可以很清晰地看到,指令3完成後,指令2中的一個地址發生了變化,這種現象的原因,我們會在後面進行分析。
指令4:這條指令與前面簡單程序中的指令3一樣,要進行條件轉移。這條指令的具體内容是:如果第8單元的數小于第7單元的數,則轉移到第1單元,如果情況正好相反,則進行到下一指令(指令5)。我們可以看到,第8單元的數“1”的确比第7單元的“10000”小,所以轉移到第1單元,重複指令1。
指令1完成後:第8單元變為
(8)2
指令2完成後:第2單元變為
即将22的結果存入第11個單元。現在你知道為什麼要提前完成指令3了嗎?是的,因為第10個單元已經被占用,新計算出的22必須被送入下一單元。
完成指令1、2之後,我們得到了如下數據:
(8)2
(9)1
(10)12
(11)22
指令3完成後,第2單元有了新變化:
這意味着計算機已經做好将計算結果存入下一單元(即第12單元)的準備。你一定已經發現,目前第8單元裡的數據仍然小于第7單元裡的數據,所以執行指令4的方式仍舊是回到第1單元。
計算機再次完成了指令1和指令2,我們得到的數據為:
(8)3
(9)1
(10)12
(11)22
(12)32
就像你看到的那樣,計算機會按照這個程序,不停地将平方數的計算進行下去。等到第8單元中的數變成10000之後,這種計算才會停止。因為計算機按照程序算完了從1到10000全部整數的平方數,這時第8單元裡的數已經不再比第7單元裡的數小,指令4不會再要求轉移至第1單元,而是進行到下一指令,指令5的命令就是“停機”。
下面來看我們要分析的第二個程序,這個程序相對複雜一些:解方程組。當然,這裡所給出的仍舊會是一個被簡化了的程序,如果你有興趣,也可以将它完整地寫出來,這個方程組是這樣的:
解方程組,這并不難:
解出這個方程組,你至少也要花上幾十秒的時間,但計算機解幾千個這種方程組,最多隻需要1秒鐘。
假設有下面一些方程組:
其中a、b、c、d、e、f、a'、b'、c'……都是已知的常數。
我們來看看讓計算機解這些方程組所用的相應程序:
指令1:将第28單元與第30單元裡的數據相乘,将結果存入第20單元,即将ce寫入第20單元。
接下來依此執行指令2~6,完成後第20~25單元裡的數會變為:
(20)ce
(21)bf
(22)ae
(23)bd
(24)af
(25)cd
指令7:用第20單元裡的數減第21單元裡的數,将結果存入第20單元,即将ce-bf寫入第20單元。
接下來依此執行指令8~9,完成後第20~22單元裡的數會變為:
(20)ce-bf
(21)ae-bd
(22)af-cd
指令10和指令11要求完成除法:
并将結果記入卡片。
到此為止,第一個方程組中的未知數就全部解完了。
那麼其他指令的作用是什麼呢?本程序的第12~19單元是使計算機解第二個方程組的指令,其中指令12~17是要求計算機分别計算第1~6單元裡的數與第19單元裡的數之和,再将結果存回第1~6單元。指令17完成後,第1~6單元裡的數據發生了如下變化:
(1)×34 36 20
(2)×33 37 21
(3)×32 36 22
(4)×33 35 23
(5)×32 37 24
(6)×34 35 25
指令18要求轉移到第1單元。
在接下來執行指令的過程中,第1~6單元裡的數據會發生什麼變化呢?很簡單,前兩個地址的編碼不再是26~31,而是變成了32~37。也就是說,機器反複進行着同樣的運算,隻是這一次是從第二個方程組各系數所在的第32~37單元選數,而不是存貯着第一個方程組各系數的第26~31單元了。第二個方程組就這樣解完了,同樣的方法,機器繼續解第三個方程組,甚至更多的方程組,直到将要求解出的方程組全部解完為止。
分析上面兩個程序的過程讓我們清楚地意識到學會正确編寫程序的重要性。機器靠“自己”其實是什麼都不會做的,它隻會完成人交給它的程序。這些程序種類繁多,比如計算平方根的程序、計算對數的程序、計算正弦函數的程序、解高次方程的程序,當然還有我們所提到過的下棋程序、翻譯程序等。一個明顯的特征是:人要求計算機做的工作越複雜,交給它的相應程序就會越複雜。
計算機還有一個重要的功能,那就是編寫程序,但這需要人首先交給它一種“編程程序”,有了這種“編程程序”,計算機就能按照程序中的指令自動編寫出相應的程序來。編程工作通常是非常繁重的,這種編程程序的使用,能大大減輕人工編程所要承受的“沉重”負擔。(俄.别萊利曼)
有話要說...