陳凱 上海市位育中學(xué)
《周易·系辭》說(shuō):“天一、地二、天三、地四、天五、地六、天七、地八、天九、地十;天數(shù)五,地?cái)?shù)五,五位相得而各有合。天數(shù)二十有五,地?cái)?shù)三十,凡天地之?dāng)?shù)五十有五?!敝芤姿f(shuō)的這種取自然數(shù)中前5個(gè)奇數(shù)和前5個(gè)偶數(shù)相加和為55的情形,大概是古人覺(jué)得55這個(gè)數(shù)字有著非同一般的寓意。實(shí)際上,其他數(shù)列的運(yùn)算中也常能見(jiàn)到55,如連續(xù)取5個(gè)相連的三角形數(shù)3、6、10、15、21的和是55,1、2、3、4、5的平方數(shù)之和也是55,斐波那契數(shù)列的第10項(xiàng)也是55。這些運(yùn)算或許可以給算法教學(xué)帶來(lái)些許趣味。
有學(xué)者認(rèn)為要從計(jì)算工具使用的角度,來(lái)揣摩古人對(duì)于數(shù)的理解。[1]例如,簡(jiǎn)單地?cái)[放2根算籌,自然而然就會(huì)在中間形成1個(gè)空位,這就是天一地二說(shuō)法的由來(lái)。筆者由此想到,古人在使用算籌來(lái)計(jì)數(shù)時(shí),表示每一位數(shù)字最多用5根算籌,為了表示6,就需要用一根方向不同的算籌代表5根算籌。圖1所示就是一種縱式的算籌擺放樣式,當(dāng)數(shù)字超過(guò)5時(shí),就用一根橫放的算籌代表5。如果用10根算籌擺放成55,那么無(wú)論是十位數(shù)加1,還是個(gè)位數(shù)加1,都會(huì)使算籌的擺放形態(tài)發(fā)生重大的變化,這或許是55的另一個(gè)特殊之處吧。
圖1 縱式算籌擺放樣式
一般人大概不太會(huì)注意到,算籌加1運(yùn)算有其奇特之處,在5向6變化過(guò)程中,對(duì)于縱向擺放的算籌,事實(shí)上并非滿5發(fā)生變化,而是滿6才發(fā)生變化,當(dāng)縱向算籌滿6時(shí),需要將縱向的5根算籌換為1根橫向算籌,同時(shí)留下1根縱向的算籌。而在9向10變化的過(guò)程中,對(duì)于所有算籌,也可以看成是滿6發(fā)生變化,當(dāng)在4根縱向算籌和1根橫向算籌的基礎(chǔ)上再加上1根算籌,就需要將所有縱向算籌和1根橫向算籌全部清空并進(jìn)位。橫式算籌擺放方法如圖2所示,如果將數(shù)字5用擺成橫向的1根算籌來(lái)表示,就會(huì)和橫式算籌擺放樣式中數(shù)字1所使用的圖樣發(fā)生混淆。可見(jiàn),算籌樣式的成型,與編碼的唯一性有關(guān)。
圖2 橫式算籌擺放樣式
用算籌做加法,一般采用兩種方法,其一是逐個(gè)增加算籌并實(shí)施算籌滿6時(shí)的變化,其二是采用算籌歌訣做快速的變化。筆者未查閱到完整的算籌歌訣,但因?yàn)橹樗銓?shí)際就是從算籌演化而來(lái),因此,珠算口訣直接就可以用于算籌,如“六上一去五進(jìn)一”的口訣,對(duì)算籌的使用,就是指當(dāng)已有數(shù)字存在上籌(縱式中的橫杠或橫式中的豎杠,借用珠算中上珠的稱謂,暫且稱作上籌)的時(shí)候,為了加上數(shù)字6,就需要移除上籌,再添加上1根算籌,同時(shí)進(jìn)位添加1根算籌。很顯然,這就是一種算法。這種算法很適合于人來(lái)使用,而且,根據(jù)算籌的計(jì)算原理發(fā)明出算盤(pán)之后,采用這樣的算法會(huì)使得計(jì)算速度有極大的提高。但對(duì)于某個(gè)完全自動(dòng)化運(yùn)轉(zhuǎn)的裝置來(lái)說(shuō),采用這樣的算法卻是徒增麻煩??梢?jiàn),哪一種算法更適用,與可用和被使用計(jì)算之物有關(guān)。
將算籌的變化和用計(jì)算機(jī)模擬算籌的變化這兩件事聯(lián)系在一起,就能發(fā)現(xiàn),實(shí)現(xiàn)“如何變”的方法是極其豐富的。算法之變和人們可借助的計(jì)算之物有著密切的關(guān)聯(lián),這里的“物”指的既可能是物質(zhì)實(shí)體,也可能是一種虛擬物,
例如,可以利用if語(yǔ)句編寫(xiě)簡(jiǎn)單的程序,將數(shù)字轉(zhuǎn)化為算籌的擺放樣式,為簡(jiǎn)便起見(jiàn),這里暫且只考慮輸入一位數(shù)的情況。方法一如圖3所示,程序中用“|”代表1根算籌,用“____”代表1根上籌,程序中“ ”的作用是回車(chē)換行,目的是用上下兩行符號(hào)拼接成一個(gè)類似算籌擺放的圖樣。為后續(xù)行文方便將此方法稱為方法一,這種方法體現(xiàn)出一種映射關(guān)系,即對(duì)于輸入的數(shù)字符號(hào),一定有其對(duì)應(yīng)的輸出的算籌擺放樣式。
圖3 一種將數(shù)字轉(zhuǎn)化為算籌擺放樣式的程序代碼
如果將變量x視作某物,將分支結(jié)構(gòu)的語(yǔ)句也視作某物,若在頭腦中將語(yǔ)句與變量之間的協(xié)同變化比擬成某實(shí)體裝置的變化,則想象出來(lái)的場(chǎng)景很可能是會(huì)有很大差異的。例如,可以想象變量x是一個(gè)帶有某種屬性的不動(dòng)的物體,而分支結(jié)構(gòu)的機(jī)械裝置則會(huì)獲取其屬性狀態(tài)并給出相對(duì)應(yīng)的輸出;或者,變量x是一個(gè)運(yùn)動(dòng)著的物體,由某個(gè)類似流水線的裝置將其載入到某個(gè)判別裝置中……這樣的想象能讓人發(fā)現(xiàn)頭腦對(duì)于虛擬之物的利用是超越物質(zhì)實(shí)體的,在想象過(guò)程中,判別裝置的行為好像一個(gè)黑箱,其內(nèi)部究竟是如何工作的,則是更難想象出來(lái)的事情。
另一種實(shí)現(xiàn)方法是將算籌所有的擺放樣式都存放于列表中,然后將輸入的數(shù)字作為索引號(hào),從列表中調(diào)取出擺放樣式。這里將其稱為方法二(如圖4)。
圖4 從列表調(diào)取算籌擺放樣式
這些存儲(chǔ)在列表中的圖樣很容易存儲(chǔ)到其他存儲(chǔ)器中,這樣就容易實(shí)現(xiàn)數(shù)據(jù)的共享,在一定程度上體現(xiàn)出存儲(chǔ)數(shù)據(jù)的意義。類似的方法有時(shí)會(huì)在計(jì)算機(jī)的算力有限時(shí)使用,如一些單片機(jī)在進(jìn)行比較復(fù)雜的函數(shù)計(jì)算時(shí),為了加快計(jì)算時(shí)間,就會(huì)采用數(shù)學(xué)計(jì)算和查表結(jié)合的方法來(lái)得到函數(shù)計(jì)算結(jié)果。[2]
可以想象某個(gè)機(jī)械裝置根據(jù)用戶輸入的特定序號(hào),到存儲(chǔ)空間中選取出相應(yīng)的圖樣。想象中的工作場(chǎng)景顯然和方法一是有很大區(qū)別的。
不妨將先前的程序代碼與圖5所示的方法三的程序代碼做一個(gè)比較。由于算籌圖樣在增加的過(guò)程中有一定的規(guī)律,所以,可以通過(guò)數(shù)字的比較來(lái)判斷是否滿6,由此確定是否要添加1根上籌,而其他縱向擺放的算籌都可以自動(dòng)化批量生成。雖然說(shuō)這三種方法都自動(dòng)化地實(shí)現(xiàn)了數(shù)字轉(zhuǎn)換為算籌擺放樣式的工作,但方法三這個(gè)自動(dòng)化裝置的內(nèi)部構(gòu)造本身存在著某種自動(dòng)化,方法一和方法二的自動(dòng)化是針對(duì)使用者來(lái)說(shuō)的,而方法三的自動(dòng)化是針對(duì)裝置的制造者來(lái)說(shuō)的,如果方法三的自動(dòng)化裝置是一個(gè)實(shí)體裝置,其設(shè)計(jì)和制造的難度顯然是要高于前者的,相對(duì)前者,它還要實(shí)現(xiàn)構(gòu)造上的自動(dòng)化,具有一定程度的元自動(dòng)化的特征。
圖5 使用分支結(jié)構(gòu)實(shí)現(xiàn)數(shù)字轉(zhuǎn)化為算籌擺放樣式的程序代碼
用數(shù)字乘上字符串是Python中特有的方法,如果使用其他程序語(yǔ)言,就需要采用循環(huán)結(jié)構(gòu)的語(yǔ)句來(lái)批量按數(shù)字生成縱向的算籌圖樣。如果將Python語(yǔ)言視作虛擬物,那么這種物具有其他程序語(yǔ)言所不具備的特征,王榮良老師提出,算法的學(xué)習(xí)需要體現(xiàn)計(jì)算模型的構(gòu)造過(guò)程,學(xué)生需要用具體編程語(yǔ)言來(lái)表達(dá)算法,這不是單純用流程圖能替代的。[3]筆者從計(jì)算之物能力切入進(jìn)行思考,也能得到同樣的結(jié)論。
這里有一個(gè)有趣的問(wèn)題,如果是由人來(lái)擺放算籌,那么此人頭腦中的過(guò)程,是更接近于方法一、方法二還是方法三呢?設(shè)想某人初學(xué)算籌,在開(kāi)始階段,大概是必須要記得滿6就將5根算籌換成1根上籌,這就需要簡(jiǎn)單的邏輯判別,比較接近于方法三的程序代碼中分支結(jié)構(gòu)判斷的行為,如果此人使用算籌已經(jīng)非常熟練,那么估計(jì)頭腦中就會(huì)建立起牢固的數(shù)字和算籌擺放樣式的對(duì)應(yīng)關(guān)系,則更接近方法一和方法二代碼的行為方式。
甚至于可以單純使用數(shù)學(xué)模型來(lái)替代分支結(jié)構(gòu)的邏輯判斷,程序代碼如圖6所示。
圖6 采用數(shù)學(xué)模型實(shí)現(xiàn)數(shù)字轉(zhuǎn)化為算籌擺放樣式的程序代碼
這種方法距離人的頭腦的行為方式就非常遠(yuǎn)了,如果不是有意要利用數(shù)學(xué),人們的頭腦幾乎很少用這樣的方式來(lái)解決日常性的問(wèn)題。假設(shè)有某個(gè)實(shí)施判別動(dòng)作的機(jī)械裝置,如果這個(gè)機(jī)械裝置內(nèi)部是借助數(shù)學(xué)運(yùn)算來(lái)進(jìn)行決策的,那么人的頭腦是很難想象出這種數(shù)學(xué)運(yùn)算是如何與裝置內(nèi)部物質(zhì)實(shí)體的變化相關(guān)聯(lián)的。這就說(shuō)明,計(jì)算機(jī)程序中的數(shù)學(xué)公式已然成為一種可用于計(jì)算的虛擬物,它和數(shù)學(xué)課堂里的數(shù)學(xué)公式的意義是有所不同的。同時(shí),計(jì)算機(jī)之所以具有當(dāng)前的計(jì)算能力,和底層的數(shù)學(xué)模型是密切相關(guān)的,人們之所以很難發(fā)現(xiàn)這些底層數(shù)學(xué)模型是如何工作的,是因?yàn)槿藗兯佑|的系統(tǒng),是由底層模型一層層虛擬出來(lái)的某種計(jì)算模型。
某些計(jì)算模型對(duì)實(shí)現(xiàn)算籌擺放樣式生成相當(dāng)有用。例如,可以借助字符串重寫(xiě)模型來(lái)實(shí)現(xiàn)將數(shù)字轉(zhuǎn)換為算籌擺放樣式的功能,程序代碼如圖7所示。這種方法相當(dāng)于是將數(shù)字所對(duì)應(yīng)的算籌全部擺放到桌面上,然后將其中6根算籌替換成1根算籌和1根代表著5根算籌的上籌。這種方法顯然很不符合人的思維習(xí)慣,但對(duì)于一個(gè)具有替換功能的裝置來(lái)說(shuō)——如果的確有的話,實(shí)現(xiàn)起來(lái)卻相當(dāng)簡(jiǎn)單。但這樣具有替換功能的裝置卻是不太容易制造出來(lái)的,雖然Python中有replace函數(shù)可用,但本質(zhì)上,是因?yàn)槭紫扔辛薖ython這種圖靈完備的計(jì)算裝置,然后才在此基礎(chǔ)上編寫(xiě)出replace函數(shù)。所以說(shuō),雖然字符串重寫(xiě)模型很容易實(shí)現(xiàn)算籌樣式變化,但這個(gè)模型本身卻是不容易構(gòu)造出來(lái)的。而其他多種計(jì)算模型,如元胞自動(dòng)機(jī)、Tag系統(tǒng)等,在實(shí)現(xiàn)算籌擺放樣式的模擬上都比較困難,而如圖靈機(jī)、時(shí)序數(shù)字電路這樣的計(jì)算模型在實(shí)現(xiàn)時(shí)就相對(duì)容易一些。有意思的是,人們可以用一種計(jì)算模型來(lái)模擬另一種計(jì)算模型,如用元胞自動(dòng)機(jī)來(lái)模擬圖靈機(jī),然后用圖靈機(jī)來(lái)模擬算籌擺放樣式。
圖7 用字符串替換的方法實(shí)現(xiàn)數(shù)字轉(zhuǎn)化為算籌擺放樣式的程序代碼
Python中的replace函數(shù)將替換功能內(nèi)部的復(fù)雜性掩蓋了起來(lái),替換的實(shí)現(xiàn)并非自然而然的。設(shè)想一下,如果現(xiàn)實(shí)世界中存在某種神奇的自然之物,可以實(shí)現(xiàn)符號(hào)編碼的匹配和替換,那么人們或許就會(huì)直接利用這種東西來(lái)實(shí)施自動(dòng)化的計(jì)算,并且演化出各種基于匹配和替換的算法了。對(duì)計(jì)算的實(shí)現(xiàn)而言,人思維中的自然的變化和現(xiàn)實(shí)世界中自然的變化是很不相同的,人需要利用自然界中的自然之物的變化,去構(gòu)造出一種能夠模仿人的思維變化的東西。莊子說(shuō),“圣人者,原天地之美而達(dá)萬(wàn)物之理,是故至人無(wú)為,大圣不作,觀于天地之謂也”,前半句很有道理,后半句卻值得商榷,假設(shè)人腦所構(gòu)造的計(jì)算模型無(wú)法由實(shí)際的計(jì)算裝置開(kāi)展直觀地運(yùn)算,那么人在通達(dá)萬(wàn)物之理的路途上就會(huì)遇到很大的阻礙。