2012年4月1日 星期日

Spreadsheet calculation in Charming FORTH

曾慶潭2012-04-02於紐西蘭
Ching-Tang Tseng
ilikeforth@gmail.com
http://forthfortnight.blogspot.com

目前,全世界的大學生,最常使用的計算軟體,可能就是Excel。不可諱言,這個原來被稱為『電子試算表』(Spreadsheet)的特殊軟體,使用起來,確實有其特殊的便利性,我也偶爾使用。
很久以前,它還被稱為Lotus 1-2-3的時代,我曾以這種軟體,為生產磁粉心的公司,設計批量產品所需要的隨貨特性數據單據,其中要用到簡單的統計學計算,根據測量數據換算成隨貨報表,提供下游工廠使用。還為設計完成的程式套件,寫過詳細的操作說明,對電子試算表軟體的性能有些認識。
他山之石可以攻錯,一套幾十年來都能被許多人接受的軟體使用觀念,算得上是他山之石,我因此而在設計FORTH程式時,經常取其長處試行攻錯,此處的『攻錯』,我解釋成『改置』的意思。
用過我所設計之ABC FORTH數學計算系統的人,一定見過我在系統程式中強調的數據輸入標準用法,就直接令某一變數等於某值,形如下列式子:

LET I = 789 或
LET { X ( 3 2 ) = 6.02E23 } 或
LET [ Z = -1.87 + 3.5 i ]

這樣的用法,既直接又簡單,人人易懂,人人會用。其基本原理,就是源自於電子試算表系統中,數據輸入的觀念,只不過是在該套裝軟體中,此處所稱的『變數』,都成了『單一個方格』了。
也許有人認為,BASIC程式語言出現的年代,比電子試算表更早,所以應該說成是電子試算表學BASIC才對。誰才是觀念領先者?並不重要,但這樣子輸入數據,就是最簡明的方法,倒是不爭的事實,因此,跟著用是對的。
這一次,我想進一步詳談電子試算表系統中的另種特性,並以極其簡單的標準FORTH程式,實現類似功能,展示另一套能讓任何FORTH系統,均可輕易執行得出來之特殊應用技術。
這種技術是FORTH天生就具有的本能,可是,我未詳加解釋之前,您可能並未體認到FORTH系統能這樣子執行數學計算,其用法可以少用堆疊,簡直就跟電子試算表的用法完全一樣。
我一直在設法傳播FORTH技術,尤其是讓FORTH來執行數學計算的技術。有時,技術的傳承,不能單純只講FORTH的指令,系統概念也很重要,應用方法也很重要,應用對象的學問也很重要,將前述幾項重要東西揉合在一起,整理出關鍵因素,然後才設計程式的理念也很重要。我所寫過的網文,都具有這些內容。因此,您讀通網文後,可以學到許多FORTH以外的學問,這一篇網文亦然。
許多人都用了FORTH許多年,您是否曾經注意過這麼一個問題?一旦FORTH系統執行起來之後,使用者通常都只在系統成長到字典尾端HERE之處的終點附近,操作系統,或增加新設計的程式。感覺上,FORTH系統的使用概念,就是:系統自HERE以上,可以增設程式的空白記憶體空間,應該沒有人會把它用完。
是的,三十幾年來,我也這樣用FORTH,能把系統記憶體很有意義用盡的次數,實在是屈指可數。只有例如:我要存起求得的許多質數、我要精確計算許多位數的超大數字運算、我要追蹤破解某種大容量程式、我要將所有國字發音的機能全部建進系統……等應用時才會發生,但沒幾次。遇到系統記憶體容量不夠的問題時,我當然知道如何將系統容量改大的方法,也知道容許更改上限,但這不是本文此次想要強調的重點。
這一次,讓我來告訴大家,如何把FORTH系統,從HERE以上到上限為止的記憶體空間,一次用完的用法。

簡而言之,就是把它設計成一套電子試算表。

如果這個程式很大、很複雜、很難理解,那麼,我的強調用法就會沒有意義。如果因為我這樣設計,破壞了FORTH原有的性能,使其從此之後就只能當電子試算表使用了,那麼,這樣的設計也沒有意義。如果這樣的設計僅只適用於某些特殊的FORTH系統,不具有全面可用的代表性,那麼,這樣的設計仍然沒有意義。如果人人都早就知道、早就普遍這樣使用了,那麼,也是沒有意義。
三十幾年前,我已設計過這樣的程式,有過應用經驗。因此,最近在測試64位元FORTH系統時,再度將其拿出來使用,目的就是用它來測試系統,結果出現了一些怪異現象,自己對新硬體裝備的內容,一時還搞不清楚,不敢對怪異現象妄加解釋,但來日必會清楚,有關於此一疑惑的答案,知道後才另文解說。
熟悉記憶體硬體的人,大概都聽說過熱點效應(Hot spot effect)這個術語,它指的是:人們使用記憶體的方式,通常都是某些部份的記憶體,會被經常使用,而某些部份的記憶體,通常因為使用方式的限制,恆不會輪到要被使用,結果,常被用到的記憶體,我們就稱其為因熱門而成的污點,具有經常必須變化內容的要求,相對於內容不常變化的記憶體,就會呈現較易損壞的熱點效應。
許多工程科學中,都有類似的熱點效應,基本道理都類似。有些熱點效應還是會讓熱點更熱而加速劣化問題的麻煩事情,必須重視。例如:原子爐中有一種被稱為熱通道效應(Hot channel effect)的嚴重問題,運轉者若放任這一條通道,多貢獻出許多連鎖反應後的核子能量,隨後的效果就會與熱點效應問題類似,若不重視,爐中該根燃料棒的冷卻水通道,於狀況發生時,會一發不可收拾而加速熔毀。我們在營運原子爐時,經常要檢視此一問題,讓系統保持遠離會造成熱通道效應的狀態。分析這種問題的方式,相當專業,必須根據複雜之熱傳導與核子工程混合的學問,推理出它有惡性循環的不良效應,並明確知道不良程度到底有多大?問題不容易完全搞清楚,但絕對不能不了解而逕行運轉原子爐。日本去年311大海嘯後,三個爐心熔毀事故的發生,可能跟在關鍵時刻,忽略了此一問題,有絕對的關連。我若參與其事,當然有能力以專業知識指出問題,但我沒興趣管這種事情,我現在只想搞FORTH。
事實上,我們FORTH系統中的記憶體,並沒有這麼嚴重的熱點效應問題,否則,系統豈不是很快就會故障、崩潰?但是,目前市售的快閃記憶體(Flash memory),就有這方面的問題,去年回台期間,領教過這種狀況,毀掉了攜帶回台的資料,等到確定重新格式化都救不回來之後,東西也只好丟棄了,問題就是起自於記憶體讀寫太多次數之後的熱點效應。因為,我曾將該快閃記憶體掛在USB上,以Linux作業系統執行FORTH,將快閃記憶體裝置當做模擬硬碟使用,下場就會如此,以後不再如此使用了。
但不管怎麼說,我若能將FORTH系統中通常較不使用的記憶體部份,令其容易直接發揮作用,總是一件好事。就算不考慮熱點效應問題,而讓該區域的記憶體,很容易存取必須變化的數據,就是功勞一件。而且,某些CPU硬體設計的選址方式,還故意將不可變程式與可變數據,設計成在記憶體中必須分開處理,結果,您就得採用我在此處提供的類似方法解決問題,否則難以在這種系統中使用FORTH。
誰都知道FORTH中的堆疊是一種後進先出的資料傳輸架構,許多人尤其是初學者,對於老是要在堆疊上,搞那些翻來覆去的操作指令,非常不耐煩。是的,我不諱言,我也常常不耐煩,甚至於堆疊的存在,就是常令我看不懂別人設計之程式的主要障礙。因此,我若把FORTH系統中的整個剩餘記憶體,都簡明的規劃成一套電子試算表,理所當然的對解決上述問題可以有很大的幫助。
我並不想設計電子試算表的視覺外觀,那種啟動後的視覺外觀確實很好,具有直覺的效果,但那樣設計,就會讓FORTH系統隱而不見。因此,我只能取其優良觀念,並以保持FORTH原有特性之方式來設計,這樣的設計結果,就是讓功能顯示在眼前,讓紙表存放在心頭,是一套隱形的電子試算表。
一般FORTH系統的記憶體圖譜,通常如圖一所示,這只是一個較為通用的系統記憶體規劃方式,FORTH系統並不是非得規劃成這樣的格式不可,它只是一種典型的格式,但利於本文用來解釋問題。這也只是一份簡圖,圖中也只標示出足供我們解釋問題時,所需要的相關結構,不標示其他不相關的東西。


圖一、典型的FORTH系統記憶體圖譜

圖中的兩個FORTH系統指標HERE及PAD,是整個設計的關鍵依據,兩者的內容都是恆會浮動的,每當系統因載入程式而增長時,這兩個指標之值便隨水漲而船高,您想用它時,它們的特性就是見官大兩級及一級,PAD恆高於HERE,HERE恆高於系統。我因此而設計了另一個見官大三級的新指標,命名為PIA,P指的是類似於PAD也恆高於PAD,I指的是整數(Integer),A指的是陣列(Array)。當然,附有浮點計算功能的系統,就能依樣設計出PRA,其中的R指的是實數(Real number),也就是浮點數(Floating number),但參考基準起點,都可以毫無問題的就從HERE往上加1000個位元組(Bytes)的量作為起點。
依圖示看來,我所設計的隱形電子試算表規格,只有起點,沒有終點。如要嚴格討論它的終點,那就是決定於系統能處理的單整數之上限。但是,現行的一般系統,若以微軟的作業系統為設計依據時,上限便取決於整個系統被宣告成的記憶體總使用量,而一般系統又常將數據堆疊與回返堆疊規劃在記憶體的頂部,因此,我規劃出來的上限,可以說就是系統堆疊使用區以下的位置了。其大約位置,可以直接執行SP@,再拓印(『.』,dot)出數據而獲得。
起點為什麼要以另加1000的數量來規劃?因為PAD通常被用來作為字串緩衝區的起點,此區域的用法,就像用後就丟棄的拍紙簿(Pad),想處理字串內容時,習慣上都送到這裡來集中處理,現行Win32Forth系統中,PAD = HERE + 256,而一般處理字串時,所需要的最大長度,大約是螢幕上一列所能顯示的字元量,現行系統就是256。這些數字量都有其設定的道理,而且還考慮了彼此保持一定的安全距離,作為防禦縱深,避免互相造成破壞。我的PIA選定自HERE往上加1000的道理,也考慮了相同的因素,1000也較容易記住。
參考起點是浮動的,使用時就得適應其浮動的規格,用時必須記得,它會浮動。因此,只要您不進行任何會增長系統字典結構的操作,如定義新指令,或載入新程式時,那麼,這套隱形電子試算表內,所有單元對應到實體記憶體的位置,是不會改變的,可以任憑使用。若以設計指令來操作它時,設計完指令並編譯進系統後才執行,執行結果就也不受影響。
在Win32ForthV6.14系統中完成設計的程式,列示如下:

\ Spreadsheet calculation in Charming FORTH
\ PAD array for Integer and Real(Floating) number
\ Author: Ching-Tang Tseng, 2012-03-30, Hamilton, NZ

: PIA ( +index -- addr )
DUP 0< ABORT" Error! Positive index only!!!"
CELL * HERE + 1000 + ;

: .PIA ( +index, +/-n -- )
DEPTH 2 < ABORT" needs 2 parameters!!!"
OVER + 2DUP < IF SWAP ELSE >R 1+ R> 1+ THEN
DO CR ." PIA( " I . ." )= " I PIA @ . LOOP ;

: PRA ( +index -- addr )
DUP 0< ABORT" Error! Positive index only!!!"
2 CELLS * HERE + 1000 + ;

: .PRA ( +index, +/-n -- )
DEPTH 2 < ABORT" needs 2 parameters!!!"
OVER + 2DUP < IF SWAP ELSE >R 1+ R> 1+ THEN
DO CR ." PRA( " I . ." )= " I PRA F@ F. LOOP ;

使用簡例,實際操作如下:

FLOAD 'C:\Win32Forth 6.14.00\ISO2012\PIAPRA.F' ok
33 1 PIA ! ok
44 2 PIA ! ok
1 5 .PIA
PIA( 1 )= 33
PIA( 2 )= 44
PIA( 3 )= 0
PIA( 4 )= 0
PIA( 5 )= 0 ok
1 PIA @ ok
2 PIA @ ok
+ ok
3 PIA ! ok
1 5 .PIA
PIA( 1 )= 33
PIA( 2 )= 44
PIA( 3 )= 77
PIA( 4 )= 0
PIA( 5 )= 0 ok

2.71828E0 10 PRA F! ok
0.33E0 11 PRA F! ok
10 5 .PRA
PRA( 10 )= 2.71828
PRA( 11 )= .330000
PRA( 12 )= .000000
PRA( 13 )= .000000
PRA( 14 )= .000000 ok
10 PRA F@ ok
11 PRA F@ ok
F** ok
12 PRA F! ok
10 5 .PRA
PRA( 10 )= 2.71828
PRA( 11 )= .330000
PRA( 12 )= 1.39097
PRA( 13 )= .000000
PRA( 14 )= .000000 ok

操作出結果後,顯示現象告訴我們,以同樣方式使用於複雜的數學計算時,幾乎可以省掉使用堆疊操作指令的麻煩了,臨時數據還留在隱形電子試算表中,能被追蹤,也能被重新測試。上述簡例,只是基本現象顯示,複雜的應用,可以寫成複雜的程式來使用,讀者請自行體會。
只設計成陣列式的結構,亦有其原因,一方面就是設計起來最為簡單。另方面係陣列包括了單個變數的意義,使用者只需記得是以那一個編號來代表某一特定變數即可。
請注意,設計出PIA與PRA時,它們仍然都只使用完全相同的起始基準參考點,不需要為不同格式的資料結構,另行規劃另外的區域。使用者只需在使用時以較大差距的指標量來區隔便可。上述範例中,整數用了以指標1為基準的整數陣列,浮點數則用了以指標10為基準的浮點數陣列,相隔很遠,不會打架。
陣列結構是連續性的架構,因此,可使用迴路操作指令對其操作,我在求許多質數的程式中使用過,也在設計對一堆數據進行統計分析時使用過,用時體會到另一種感覺,如果我將這麼簡單的指令直接納入系統,讓其開機時就已存在,那麼,每逢需要使用之時,可以大量省去每次都得重新宣告變數或陣列的麻煩,至於隱形電子試算表中的那一個位置才代表指定變數?不便於記憶之問題,只需以說明方式,標註於源程式中便可。
其實,在Win32Forth的系統規劃中,已經將程式與資料的形成,分開到三塊不同的記憶體中去了,因此有SYS、APP及code三套存取指令,但是,系統中HERE以上之記憶體空間規劃方式是固定的,系統依然讓HERE以上的記憶體空在那裡。我見過國際上有幾個大型公開程式,因須大量且不定量的使用記憶體來儲存或操作數據,就改採此處同樣的設計方式,也都是採用隱形的設計方法,然後直接使用,來達到目的。
有感於此,我便希望將這樣的用法,納入系統,讓PIA與PRA甚或PZA都能成為原生、現成指令(Primitive instruction)來使用。即使是不定長度的常用資料,如字串、超大數字或基因圖譜,也能以類似方法規劃進隱形電子試算表來處理。利用它們的首個單元,作為個別資料的連結欄,就能輕易的規劃出這種使用方式。事實上,我早已這樣設計系統很久了,如果大家都不用FORTH,我找誰談這些新觀念、新精神?這些東西只好留在雲端,永供後人憑弔了。
上述程式,全用標準指令設計,能適用於各種FORTH系統,我也有能力將其改設計成矩陣式的規劃格式,加進我所設計的ABC FORTH數學計算系統,那樣做,就能實現一般標準電子試算表套裝軟體的所有功能,全用人類慣用的中算符表示程式,並讓每個單元在程式中出現時,呈現該有的性質。此處公佈的這四個極簡單指令,只是一套觀念性的引言,但能告訴大家,再設計格子顯示畫面,配合輸出、輸入,用FORTH設計出一套獨立的電子試算表套裝軟體,已非難事。硬要搞這種東西,我就有能力設計出別人都不曾有過的功能,例如:要電子試算表講話,難嗎?我辦得到。我之所以不願去惹這種事情,只因為我只想搞我自己喜歡的FORTH,不再作它想。
其實,這樣的用法,原本就是FORTH的天性,上述四個指令,只是重新規劃飛取(Fetch,”@”)與存妥(Store,”!”)兩個標準指令的使用規矩而已,了無新意。可是,電子試算表也僅只是根據同樣的觀念設計而成的,我若不提醒,有誰會去思考它們之間的關聯性?Excel把數據顯示在方格中的樣子,跟我把數據印出到螢幕上的基本哲理是相同的,我只是在進行他山之石可以攻錯的工作,結果只有四個這麼簡單的指令,非常適合初學者仔細學習與研究,文章也談到了系統結構。

因懷舊而重提此程式,是為了要測試64位元的FORTH系統,昨晚狠狠的下令系統執行下列工作:

594197594197594197 DUP DUP DUP DUP DUP DUP ok
33 SWAP PIA ! ok
44 SWAP 1 + PIA ! ok
5 .PIA
PIA( 594197594197594197 ) = 33
PIA( 594197594197594198 ) = 44
PIA( 594197594197594199 ) = 0
PIA( 594197594197594200 ) = 0
PIA( 594197594197594201 ) = 0 ok
@ ok
SWAP 1 + @ ok
+ ok
SWAP 2 + ! ok
5 .PIA
PIA( 594197594197594197 ) = 33
PIA( 594197594197594198 ) = 44
PIA( 594197594197594199 ) = 77
PIA( 594197594197594200 ) = 0
PIA( 594197594197594201 ) = 0 ok

竟然還能正常的工作!我的電腦只裝了8G Bytes的記憶體,只有10的9次方之實體可選址範圍,上述狀況是10的18次方,而且每個單元一用就是8個位元組,這樣用是餓食記憶體(Memory hungry)的使用方式,容易出問題,且不容易探索問題出在那裡? 我一時也搞不清楚狀況,不知道它算成的東西到底放到8G中的甚麼地方去了?我請我太太來觀賞,她說得對:『Should be somewhere.』。我只好戲稱,可能是連到陳爽的電腦上去了,也許應該用Skype呼叫大師兄幫忙檢查一下,我的數據是不是跑到您那兒去了?否則豈不是有鬼?

****************************************

在仔細研讀系統的源程式後,我已知道問題所在,補記說明如下:

原始系統的設計人,利用編譯出系統時,就可宣告系統佔用記憶體上限總量的規劃機會,令系統內所有的選址操作,都設計成:『指定位址之值』必須先行與『設定上限』進行邏輯『AND』的運算,然後才進行實際的選址操作。

如此一來,不管您在64位元系統中,使用任何一個無論有多大的可用整數,作為位址之值,經過AND運算之後,結果都恆小於『設定上限』。

系統裡面沒有鬼!

我認為我們的這個世界根本沒有鬼。認為有鬼的人,都是因為自己一時搞不清楚狀況,才會認為有鬼的,就跟上述這個鬼故事一模一樣。

****************************************

說實在的,我們這些玩FORTH的人,根本就買不起10的18次方個Bytes的RAM記憶體,來裝到自己的電腦上。唯一的希望,大概就是等陳爽把雲端FORTH搞通了,然後跟雲端營業公司商量清楚,提供我們一次搞定那麼多記憶體的服務,裝它一套64位元的FORTH,就算只能跑整數也無所謂了。我大概會首先上去試一下本領,就用一個小小的程式,一次就把記憶體從頭到尾測到底,確定他們沒騙我們。再裝一個小程式,一路把可以試出來的質數,全部給存進那個FORTH系統,不好意思,幾分鐘內,我個人就會霸佔這個系統,然後宣佈它實在還不夠用,請雲端服務公司繼續擴大支援,我還有許多惡食記憶體的題目可以執行,能幫他們做點誇張性的廣告。
我為什麼會用上面那個中央數字『594197』?因為它比較好記,意思是『我就是要搞怪』(Naughty is naughty),而且連搞三次。
通常,我寫成的系統性基底程式都不太多,而且幾乎都簡單到會令觀眾笑掉大牙的程度,上次參與過中文語音輸出程式設計活動的同好,應該見過我的習性了,那個程式最後只剩A4影印紙半頁的鬆散成果,我的FORTH系統就能講國語了。
設計程式時,我很強調對事物的觀念與對問題的了解,如此才能找到解決問題的最佳方法。搞好FORTH,需要這些東西,這些東西卻都不是一般人能夠輕易寫得出來的,想學的人,就請好好的學,學問相當廣泛。
不想學也沒關係,就像上述程式,表面內容根本就沒什麼。
我設計的東西不會破壞系統,當我將其強加進系統,固定下來之後,這些指令絕不會造成困擾,您若不想用,可以不用碰它。這些簡單東西,卻是我的創作,我也僅以網文正式宣告。

測試過W7作業環境後,發現續用XP能執行的系統時,還是有視窗輸出或輸入,會因一列超過256個字元而自動消失掉一個字元的問題。微軟賣東西給我們,每台電腦拿走了5000台幣,我已買過好幾台了,他們應該修正這項長期以來一直欺負人的嚴重錯誤,卻不做,真夠可惡。
如果有人以此系統設計原子爐爐心上千根燃料棒冷卻水的溫度顯示時,某一危險通道冷卻水的高溫120度,因需跳列輸出顯示,變成了常溫20度,工程人員因而不做處置,然後又因熱點效應,瞬間熔毀了燃料棒,接下來就是三哩島事故。
這種問題,比西元1999年時,電腦專家一直不斷用來騙我們的千禧虫,更為可怕,因為它已經是實際如此了。基本作業系統內的錯誤,能修正卻不修正,請問,微軟為不為人類的核子災難負責?如果有人想告它,缺乏明證,我這裡可以提供。
我們已經非常習慣於XP環境的中文打字操作,轉到W7去後,又要重新開始適應新的另套困難操作方式,這幾天因為微軟的這些作風,而讓我有嚴重的失落感與挫折感。
很可笑,多少年來,我慣用國字注音符號輸入法輸入中文,我老是打不出『泵』字,每次遇到它,就只好以『油泵』之辭來先行輸入『油』字,然後再以挑選後續跟用字方式,選得『泵』字,如果不要『油』字,而要『水』字,就回頭將『油』字刪除,再輸入『水』字,然後跳格,繼續幹活,非常麻煩,而且麻煩了許多年,氣死我也。
後來,因為搞中文語音輸出,全面清查系統中的中文國字,才發現,原來是應該唸成『ㄅㄤˋ』的『泵』字,被微軟發行的作業系統,改放到『ㄌㄧㄡˊ』去了。還有許多字的下場也是如此,微軟負過什麼責任?這家公司能在台灣控告任何人盜用他們的系統嗎?我們的司法、執法機構,何須為這麼惡劣的公司服務?為什麼不公公正正的發佈全球通緝逮捕令?抓他們全公司的人,來處理他們多少年來都不負責任的問題,這些罪行絕非單純的只是破壞中國文化而已。
現今,台灣是不是還像思想落後的美國那樣?有錢有勢才能享受司法?如果政府敢以『是』來辦事,那麼,全國受害的人民,就可以立刻發動革命,打倒這樣的政府。全世界的中國人,都應該建立這樣的現代思想,也應該向美國輸出這種正確的革命思想,要他們修正落後的行事規矩,跟上時代潮流。
微軟騙走了全國多少人的錢?害我們損失了多少的時間?承受過多少傷腦筋的問題?我們經常要因他們的作風而氣急敗壞、情緒低落。社會上的動亂,可能跟這家具有帶頭性質的公司,這樣子長期賺不道德的錢很有關係。『亂來』者都不應該給予賺錢的『自由』,社會才能長治久安,以最大力度懲罰微軟這家公司,是必要的,不能讓它像以前的RCA,徹底毒化、永久摧毀了台灣許多的國土,一聲喊倒,就全部跑光了,這就是落後的美國行事規矩。要不然,台灣整個社會,最近才凸顯出來,有著許多憑『亂來』而賺錢的公司,政府能夠執法處罰他們嗎?不打微軟就別打他們。帶頭『亂來』者就是最大的『亂源』,必須消滅,政府自己更不可以跟著亂,國家才能健康發展,該消滅任何亂源時,就得直接消滅,不要遲疑。