2026年4月15日 星期三

邏輯運算(Logic operation)

邏輯運算(Logic operation)


曾慶潭 Ching-Tang Tseng
ilikeforth@gmail.com
Hamilton, New Zealand
16 April 2026


本文所探討的邏輯運算,為『條件整合』所需的邏輯運算,而非『位元操作』方面使用的邏輯運算。

為了讓ABC FORTH數學計算系統增添這種邏輯運算的功能,我才慎重其事的重新探討此一主題。討論的內容仍然憑藉著邏輯運算的傳統原始定義,但討論的結果,可以產生創新的作法,並實際實現將系統中的邏輯運算指令,設計成以適當的中文意思來表達,且令其在程式中的使用方式,符合中文的語法規格。

大體而言,數學計算系統中的處理對象,若能夠被明確的劃分成各個獨立模組,系統便容易規劃、設計、發展。舉例而言,ABC FORTH數學計算系統,將整數、浮點數、複數…等數字處理對象,都當作各自獨立的模組來考慮,模組化後可以大大的簡化整個系統,讓各模組的問題,只須在各模組的範圍內自行解決。

因此,在ABC FORTH系統中,欲添加邏輯運算的功能時,最佳的作法,當然也就是繼續將這項主題,考慮成一個新建的單一模組來設計程式,讓邏輯運算的位階等同於整數運算、或浮點數運算、或複數運算,是一個獨立的新模組。

事實上,邏輯運算在實際的科學應用中,原本就與各種數字的運算不相干。數字運算計算3乘2得到6,1加1得到2,配合上其他所有的運算,形成一套完整的數學體系。邏輯運算執行0與1的各種運算後,也會得到一些運算結果,但這裡的0與1不表數字,而是表真或假、對或錯、是或非、有或無、開或關、高或低…等等所謂的邏輯相對狀態,0與1僅只是借自數字系統的兩個元素當作符號,這個1也可以使用除了0以外的其它任何數字來代表,但都與數字的大小或正負意義完全無關。總而言之,邏輯運算原本就與各種數字運算無關。

邏輯學是研究理論數學、應用數學、高深數學之基礎工具,也一直都是電腦科技發展的基石,電子邏輯電路工程更是經常需要用到邏輯運算設計產品。數學計算系統不應排除邏輯運算的功能,它係電腦以執行軟體程式的方式,實踐邏輯學問,沒有邏輯運算功能的系統,性能便有所欠缺。因此,將全部的邏輯運算功能建立在數學計算系統中,是有必要的,健全的邏輯運算功能,也有助於處理人工智慧方面的程式。我將加建邏輯運算功能的方法搞成極其簡明的方式,當然也就有助於各方面的應用發展。

2010年七月,我才開始設想『如何增建處理邏輯運算的功能進入系統?』的問題,自覺很容易實現這樣的設計。但是,那時只是初步的構思,只考慮仿照一般傳統程式語言的習慣,暫時僅融入『而且』(AND)與『或者』(OR)兩個單純指令。這篇文章則進行廣泛性的探討,包括如何給予適當的邏輯算子中文名稱?我個人認為,應該研究過它們在系統程式語言中之表達位置後,方給予適當的命名,才會比較恰當。讓指令的名稱符合語言上下文的啣接要求,這樣才能有助於設計出具有優良語法的程式系統。

一般而言,若只討論邏輯運算不同的名稱,基本邏輯運算的算子共有六個,它們是:

(1) AND (2) OR (3) XOR (4) NAND (5) NOR (6) NOT。

在FORTH程式語言中,邏輯算子(Operator)所需要的算元(Operand)操作對象,除了NOT只需要先行提供一個算元外,其他五個,都需要先將兩個算元操作對象放在堆疊上,然後才能執行邏輯運算。執行的結果都只得到唯一的狀態表示值,並將其留在堆疊上,供後續指令使用。換句話說,FORTH的邏輯運算,是一種後算符式的運算。1994年訂定的ANSI FORTH指令標準中,只將前三個當作標準基本指令,後三個可以導得,設計如下:


 
: NOT	 0=		;
: NAND AND NOT ;
: NOR OR NOT ;


如果單純的以1表示『真』,以0表示『假』,來製作一份邏輯運算真假值表,NOT不製表,原為1則得0,原為0則得1,其它的邏輯運算真假值表示如下:


上述全屬邏輯運算的原始性質定義,我們透過它來討論問題。

學過電子學上邏輯電路設計技術的人,一定知道,只要根據單一種邏輯閘,NAND或NOR僅擇其一,把它當作萬用基本邏輯閘,就可以設計出另外五種邏輯閘的知識。目前,市面上販售所謂的以NAND或以 NOR單種電路製造的快閃記憶體,大概也就是依據這個道理設計而成的。

事實上,在FORTH程式語言中,我們單純的只以軟體程式來設計,也一樣可以完成這種方式的設計,只不過是我們另得配合使用簡單的堆疊操作指令來達到目的。

我們若只以NAND當萬用基本指令來設計時,其它的五個是:


 
: NOT	( n – n ) 	  	DUP NAND ;
: OR ( n1 n2 – n ) DUP NAND SWAP DUP NAND NAND ;
: AND ( n1 n2 – n ) NAND DUP NAND ;
: NOR ( n1 n2 – n ) DUP NAND SWAP DUP NAND NAND DUP NAND ;
: XOR ( n1 n2 – n ) OVER OVER DUP NAND NAND –ROT SWAP DUP
NAND NAND NAND ;

我們若只以NOR當萬用基本指令來設計時,其它的五個是:


 
: NOT 	( n – n ) 		DUP NOR ;
: OR ( n1 n2 – n ) NOR DUP NOR ;
: AND ( n1 n2 – n ) DUP NOR SWAP DUP NOR NOR ;
: NAND ( n1 n2 – n ) DUP NOR SWAP DUP NOR NOR DUP NOR ;
: XOR ( n1 n2 - n ) OVER OVER DUP NOR NOR -ROT SWAP DUP
NOR NOR NOR DUP NOR ;


這些FORTH指令簡單易懂,是初學者很好的程式設計練習指令,而且上述設計方法不是唯一解答,您若有興趣試一試自己的本領,不妨就自己另搞一套,並自行摸出如何證明自己的設計絕對正確的辦法。這些整理出來的結果,也是當初發展出eforth系統前,曾經被仔細探討過的題材,是想要將FORTH反璞歸真前的一個重要程序。

有了這些根據,我們可以開始探討如何將這些功能全部加進ABC FORTH數學計算系統的問題了。在這個系統中,若以BASIC式的方式來設計程式,則『條件整合』用的邏輯運算,只會出現在條件分支指令組IF…THEN之間,一個典型的『而且』(AND)指令使用範例如下:

100 IF ( A > 5 ) AND ( B > 5 ) THEN 700

其中,( A > 5 ) 與( B > 5 )是兩個範例條件,本文只使用它們來代表一切可能的條件,是假設性的算元,AND便對這兩個條件進行邏輯運算,所得結果用來決定是否分支到THEN後面所指示的前往位置700去?改成中文程式則為:

100 如果 ( A > 5 ) 而且 ( B > 5 ) 前往 700

這樣的程式書寫方式,幾乎與我們中國人的語言表達方式完全一致了。有這麼重要的意義在其中,就更值得為其它另外五個邏輯運算指令,好好的設計出適當使用規則。另外一個『或者』(OR)指令,性質與『而且』(AND)相當,就照上述安排,成為標準的中算符指令使用方式,非常理想,由英文譯成中文的指令名稱也很恰當,不須要再進行任何修正。

這兩個指令,還有一項特點,也就是可以連續使用無限次於IF…THEN之間,用幾次都不成問題。因為每經過一次邏輯運算之後,都只留下一個邏輯狀態值,繼續以上列中算符方式安排在程式中時,便也能繼續與後續的新條件亦即算元操作對象進行邏輯運算,直到不算了為止,仍只得到唯一的結果,供給『前往』(THEN)指令使用。

另外的四個慣常邏輯運算指令,在英文環境的適當表達方式,則與中文有所不同,這是我從上述真假值對照表中看出來的問題。

當然,表達方式可以有很多種,只要使用方式合理,使用者使用時,可以覺得足夠友善,都可以作為設計的依據,而且對我而言,都很容易設計得出來。例如:我可以懶到根本就將所有的邏輯運算當作也是一種函數來考慮,那麼,六個邏輯運算,在程式中,就可以全部統一成前算符方式,使用於程式設計中。

我在ABC FORTH系統整數體系內所設計之『位元操作』應用方式的邏輯運算,就是前算符的格式,以便讓這六個指令可以呈現函數表示式的性質,如果在IF……THEN間的『條件整合』情況,繼續延用前算符規矩,程式就必須寫成下列格式:


 
AND 	( ( A > 5 )  ,  ( B > 5 ) )
OR ( ( A > 5 ) , ( B > 5 ) )
XOR ( ( A > 5 ) , ( B > 5 ) )
NAND ( ( A > 5 ) , ( B > 5 ) )
NOR ( ( A > 5 ) , ( B > 5 ) )
NOT ( A > 5 )


系統將這些函數式的邏輯算子執行完畢之後,都只得到一個唯一的狀態值,當然就能提供後續的THEN指令使用了。可是,這樣子使用之後,就完全失去了與人類語言直接對應的關係,結果就等同於傳統FORTH中的後算符使用方式,這兩種類型都與人類慣常語言完全不匹配。

另外還有一項因素,上述AND與OR兩個較完美中算符式的設計,也是一般傳統程式語言中所採用的格式,若不跟著以同樣的方式使用,想轉譯舊程式進入ABC FORTH系統時,就會產生困擾。因此,必須保留這兩個邏輯算子,成中算符的格式來使用。

其它的邏輯算子就不是這樣了,如果生平根本就不用英文思考問題,不必管它XOR、NAND、NOR、 NOT的實質意義為何?把這些算子都譯成『與…進行某種邏輯運算』,那麼,前三個指令就設計成也是中算符就很理想,例如:

( A > 5 ) XOR ( B > 5 )

表示條件( A > 5 ) 與條件( B > 5 )進行XOR邏輯運算

至於NOT,則只好維持原來FORTH後算符的方式了,我在ABC FORTH系統中,就將英文的邏輯運算指令,設計成這樣的使用格式,但深覺它忽略了中文,不尊重我們中國人的存在。

考慮在中文程式中使用這些邏輯運算指令時,若純用中文進行思考,便能夠深刻的體會出指令名稱、實質意義,與語言規格間的重要關聯。為顧全大局,要讓這四個指令都必須以『後算符』的格式來使用,才比較恰當。為什麼?請回頭仔細看看邏輯運算真假值對照表中顯示的各種狀態,您就可以明白其中的道理。

我在台灣讀過的書本中,幾乎所有與邏輯算子有關的譯名,大約都被固定的翻譯成非常怪異難懂的名稱了。『XOR』被譯成『互斥或』,『NAND』被譯成『反且』,『NOR』被譯成『反或』,『NOT』大概被譯成『非』吧。如果要拿這樣的譯名來設計中文程式,那我寧可不設計程式了,不信請讀一讀下列用法,看看您能不能直接讀出程式的意義來?

100 如果 ( A > 5 ) 互斥或 ( B > 5 ) 前往 700

講實在話,我讀不出來。

於是,我為這四個邏輯運算指令想好了比較一致、比較恰當的中文名稱,將它們都設計成後算符的使用格式,並且在兩個條件算元操作對象之間,添加一個逗號『 , 』當作分隔符號,完成了設計。此處再度複製一份真假值表,以便就近參考,請先行觀察四個指令在表中呈現的意義,然後再看看分別被譯成的適當中文名稱,對照如下:



 
XOR		一是一非
NAND 不為皆是
NOR 兩者皆非
NOT 狀態相反


我在ABC FORTH系統中實現了這樣的設計,它們的使用規格則如下列:


 
100 如果 ( A > 5 ) , ( B > 5 ) 一是一非 前往 700
100 如果 ( A > 5 ) , ( B > 5 ) 不為皆是 前往 700
100 如果 ( A > 5 ) , ( B > 5 ) 兩者皆非 前往 700
100 如果 ( A > 5 ) 狀態相反 前往 700


如此一來,這些邏輯運算就都符合我們的中文語法了,而且想進行連續邏輯運算的程式設計時,使用小括弧,清楚的將各個條件算元操作對象,按同樣格式區分開來,也能完成沒有次數限制的邏輯運算。以前,從未有人這樣子翻譯這四個邏輯算子的中文名稱,我現在則以邏輯算子在中文話語中的上下文關係,作為考慮基礎,譯名也包括了中文的直覺意義,可以通順的使用於程式語言中,這樣做算是創舉。

我在習慣於快速中文打字的操作後,已經不再認為:給予指令四個字,例如:『狀態相反』,會比只給單個字,例如:『非』,的譯名要差了。好的指令中文譯名,應該是清楚第一,通順至上。在以打字方式設計程式的作業環境中,字有幾筆、幾劃?更不重要,今人考慮的問題,早已與前人大不相同。

邏輯運算的功能,完全能應用在任何需要邏輯運算的場合,包括設計電子邏輯電路時的應用,使用者可以在未接觸硬體前,先以執行軟體程式的方式來實現。但是這種邏輯運算,屬於『位元操作』應用方式的邏輯運算,並非『條件整合』應用方式的邏輯運算。因此,在ABC FORTH數學計算系統中,就必須使用整數體系內的六個函數式的邏輯算子來設計程式,有別於此處探討的邏輯算子。

邏輯運算是數學運算中的一門分支,本文僅只處理了六種慣用邏輯算子,如果另有新的邏輯算子產生,隨時可以迎合要求,將其加入這個完全按照自己的理念設計出來的ABC FORTH數學計算系統。

我可以不堅持自己的譯名就是最好的選擇,大家若有更高明的見解,也可以經過討論後,重新設計進系統,這就是不必受制於人的好處,我們隨時辦得到。

這樣子的研究,純粹衝著我們中國人自己的文化而來,打從幾十年前開始學習電腦程式語言起,我心中便對中國人想使用電腦設計程式時,始終受制於西方文化設計出來的規範,感到忿忿不平,如果自己完全沒有能力在這方面進行改善,那就不必空談,只能拈香跟拜(台語,表示只能忍受一切羞辱,任人擺佈的意思)。

整理出這樣的研究,它的好處在那裡?完全無利可圖,所以何必曰利?但是,如果大家都不願正視這樣的研究,那麼,只好一輩子永遠拈香跟拜。

現在不一樣了,我早已習慣於在自己的電腦上大肆使用中文,譬如打文章、寫信、作記錄、看資料、看新聞、看程式…等等,我也有能力設計出可以完全只使用中文來當指令的程式語言,那麼,為什麼不更進一步的發展?也許我的個人研究不太成熟、不夠完美、不算甚麼,但是,至少我已經能夠這樣做了,上述的中文程式語言功能,我確確實實的實現了!而且,我會繼續思考,繼續努力,繼續設計,在數學計算系統方面,別人能做甚麼,我也絕對能設計得出對等功能的系統,性能還可以中文為主,並且直接超越別人的設計!

與數學計算相關的大部份實際程式中,必須使用到『條件整合』式邏輯算子的情況非常簡單,幾乎只要準備AND與OR的功能就夠了。在進行專家系統方面的程式設計時,反而更需要全部邏輯運算的功能,尤其是如果想用中文來設計專家系統時,除了要讓執行結果絕對符合專家資格,不出差錯外,對於日後的程式維護,也要講求精簡明確,那麼,這一篇文章內所強調的要點,就會很有價值。

2026年4月2日 星期四

常微方程式之 Runge-Kutta 解法

常微方程式之 Runge-Kutta 解法


曾慶潭 Ching-Tang Tseng
ilikeforth@gmail.com
Hamilton, New Zealand
2 April 2026


本文專注於引用單一文獻,將一個標準的 FORTRAN 程式,直接改寫成 ABC FORTH 數學計算系統可以執行的程式。改寫的方式幾乎是一列一列對應式的翻譯,執行解得的答案必須與原資料文獻一致,操作的便利性必須符合現今時代潮流,內容則是一個實用的數值分析標準範例。

參考文獻源自:

Brice Carnahan, H. A. Luther, James O. Wilkes, “Applied Numerical Methods”, Chapter 6. Example 6.3. p.367 ~ p.380,

“Forth-order Runge-Kutta method - transient behaviour of a resonant circuit”

本文的主要目的,並不想詳細講解,如何使用計算機設計程式來求解常微方程式?也不想詳細介紹所謂的 Runge-Kutta method ,數值分析專門書籍內可以找到這方面的知識,上述文獻就是非常完整的標準教材。重點集中於強調:如何將任何 FORTRAN 數值分析程式改寫成 ABC FORTH 程式?並展示,大型、複雜、實用的 FORTRAN 數值分析程式很容易改寫,所得的程式,比原 FORTRAN 程式使用起來更為方便。

過去幾十年,普天之下,已不知有多少的專家學者,發表過難以計數卻都非常有用的 FORTRAN 數值分析程式。電腦科技的演進,如果會廢棄這些先聖先賢費盡心血提供出來的研究成果,那就實在是人類的悲哀了,很不幸的是,目前電腦軟體技術的走向,傾向於如此。當年,許多聖賢,公開電腦技術,研究解決數學問題所做的貢獻,都寫成程式、發表成論文,有許多都算得上是精彩的博士論文。但是,現今的電腦環境,幾乎已經不容易再去執行那些有用的程式了。本文單舉一個例子,以 ABC FORTH 數學計算系統實現這種功能。幾十年來的專家學者,在數值分析實務上所做過的貢獻,完全可以輕易的使用 ABC FORTH 數學計算系統令其重現,並且化腐朽為神奇。

本文的主題,大約是理工科系大學三年級以上的學生,才可能遇到的特別數學問題。如果 ABC FORTH 數學計算系統,能夠解決這一等級的數值分析問題,那麼處理一般性的數學計算問題就當然是輕而易舉。已經擁有 ABC FORTH 數學計算系統的使用者,請耐心的讀完本文,以這個實例學會譯寫 FORTRAN 程式,這是本章的宗旨。

常微方程如何用程式來求得解答?

大學中的常微方程課程,教材內容偏重於理論數學,專挑一些理想化了的典型常微方程,例如:線性、常數係數、低階、規則型態的方程式來解釋分析,最重要的是,要能手解求得存在的唯一解答,如此才能讓學生建立常微方程式所代表的觀念,各個理工科系的學生,各有應該專注的不同型態之常微方程,各自深入了解後,就可以應用到後續所學的專業科目上去,能用手解得到的答案,有一個專門術語,稱作解析解(Analytical solution),也就是透過數學理論解釋分析後歸納出來的答案,健全完整,考試要考。

理論上的手解方法,通常都已固定落實了,甚至於都可以寫成公式直接套用。通常的解法,是以固定的演算程序,寫出常微方程之係數尚未確定前的通解(General solution),然後,將已知的起始條件(Initial condition)或邊界條件(Boundary condition)代入通解,最後,確定通解中各項式的未定常數係數,便能獲得代表符合所有條件的特解(Special solution)。

理工科系的學生,要用這些解答來探討他所研究學習的專業科目問題,例如:機械工程系的學生,解得流體力學或熱傳導學的常微方程答案後,就可以了解系統內物理現象變化的趨勢。電機工程系的學生,解得電磁學的常微方程答案後,就容易明白電磁現象的變化。土木工程系的學生,也按同樣的方式,就能夠了解建築結構上力的分佈。化學工程系的學生,用同法來了解化學反應變化。換句話說,工程科技,一定要學常微方程,甚至於偏微方程。

上述僅用一段話,說明求解常微方程的目的,而常微方程通常都是表達自然現象的一種數學式子,能夠被手解的類型所佔比例是非常少的,科學家要大刀闊斧的合理簡化式子後,才能讓原來表示自然現象的常微方程變成可解析,這就是科學上常說的大膽假設。

現實世界中,如果學過了某門工程科學,日後工作時遇到了實際的常微方程,不能每次都用大膽假設法解問題。從事於工程工作是負有責任的,不能全憑假設解問題;較無責任問題的研究工作,有時也不搞假設,因為如果假設不成就會長期沒有進展,研究停滯不前。不能手算獲得解析解的常微方程,不一定就無法可解,科技發展到今天,有了電腦可以協助人類進行快速數學計算,產生了所謂的數值分析技術,以分析問題後採用有依據的數值計算方法,用逼近答案的演算方式求得解答,其結果同樣可以讓人類了解自然現象變化的趨勢而解決科學問題,這樣的解題方法,在學校兩小時的考場內,考試沒辦法考。

求解常微方程的答案時,使用數值分析法與使用手算推演解析解法完全不同,就比較二者在得到答案程序的差異上而言,甚至於可以說是採用完全相反的步驟與方式來獲得解答的。數值分析法一開始,就得使用唯一已經確定的起始條件點或邊界條件點,做為起算基點。古時候,有很多的聖賢應用數學家,例如:本文採用的 Runge-Kutta method 即為其中之一,研究出各種逐步演算推進到下一點的合理方法,寫成數學通式,再翻譯成電腦可以執行的計算程式,藉由電腦的快速演算能力,逐點計算,逐點推進,便可算出此後所有合乎常微方程式所有條件的答案值來。

上述兩種解法所得的答案,最大的不同點,顯示在答案的表示方式上。解析解的答案通常都是可以寫成漂漂亮亮的數學函數的解答,所有工程科系的學生都習慣見到這樣的解答。數值分析解法所獲得的答案,見不到函數表示式,僅只有好幾筆一序列長串印出的數目字,乍看之下,實在不容易看出個所以然來。然而,在應用上,兩種答案意義是一樣的,而且理論上必須相等。這就好比您在查函數表的數值時,您也看不到函數表示式一般,但可以立刻用來解決工程問題。

數值分析技術一定要用到『函數曲線繪圖程式』,利用繪製函數曲線圖形的程式,就可以用圖形來顯示上一段敘述內所得到的數目字解答,將答案繪製成圖後,您就能夠完全了解,數值分析法解得答案的意義了。

以前大學教育裡不太教這種解題技術,當時,電腦的運用沒有那麼方便,情有可原,現在的大學應該要重視這方面的教材,因為,這是一種實際的解題方法,正式的工程問題就得使用。您用得好,工程或研究就做得好,您用不好,工程或研究就做不好。只會解析解的工程科系學生,考試可能可以考得高分,稱得上是秀才。但如果秀才抗拒電腦,拒絕學會數值分析法解工程或研究問題,秀才就會經常沒有用。兩種方法都搞得很好,才能算是人才,我們的社會需要人才而不是秀才。

本文採用的大型例題,要完全研究透徹,須要仔細讀完大約五十頁的英文原文著述,是數值分析教材中一章的份量,若要全譯成漂亮的中文,就得大費周章。我創作 ABC FORTH 系統的主旨不在這裡,我就是希望今後這種文章都不必寫了,只要忠實的告訴您,題材的原始出處,您自行參考,直接取來運用,為後代子孫著想,節約人類寶貴的資源,才是主要宗旨。

這個例題是電路學上,一個分析電阻、電容、電感(RCL)三個電子元件,串聯成一封閉迴路所形成的振盪電路,它可以寫成一個二次的常微方程,來表示電壓隨時間變化的關係,希望能解得具有起始條件後電壓隨時間暫態變化的趨勢解答。


起始條件係假設迴路原為開路狀態,瞬間在電容兩端充以 10 伏特電壓,並立刻將開路改成閉路,則電容兩端電壓隨時間變化的二次常微方程表示式,及這樣的初始條件可以表示式為:

LC*(d(dV/dt)/dt)+RC*(dV/dt)+V=0
V(0) = 10
dV(0)/dt = 0

三個電路元件的物理量假設為:
電容值固定為 C = 2 * 10 ^ -6 farads
電感值固定為 L = 0.5 henries (程式中被表示為 HL )
電阻值可選擇為 R = 0, 100, 1000, 1500 ohms
電容兩端瞬間起始電壓固定為 10 volts
分析時步進間隔值分採 H = 0.00001, 0.0001, 0.001, 0.002, 0.005, 0.01 sec
分析最長時間設定成小於 0.02 秒,亦即 TMAX < 0.02 sec

這個典型的例題是屬於一個可以手算求得解析解的問題,因此,解析解也被用在程式中直接計算,以便將所得結果,與使用 Runge-Kutta method 數值分析解法所得的答案,進行直接比對,驗證數值分析法的合理有效。

詳細的分析與討論,本文不再贅述,有興趣的讀者請自行參考文獻。

這個程式可以被應用到求解所有的常微方程上去,包括高於二次以上的高次常微方程,前處理分析出來的相關通式改寫成程式後,被安排在 MAIN 指令的第 120 及 130 兩列中,想應用於別的常微方程式問題時,就得在這裡替換通式表示式,詳細過程仍請參考文獻後仿照應用。

我可以把這個程式寫得更好、更有效率、更有通用性,但達不到教大家直接改寫 FORTRAN 程式進入 ABC FORTH 系統的效果。因此,我以最大的耐心,逐列翻譯。除了前文曾經提及的輸出、輸入全自創,而不改寫外,整個程式幾乎沒有需要大肆更動之處,簡單的程度,就好比將四川話翻譯成普通話那麼簡單。 FORTRAN 裡面有一個可以多重分支,GO TO (1,2,3,4,5), M 的指令,也很容易依理改寫。程式改寫完畢後的執行結果,當然要與原文列印的結果相同,最多僅能有小數點後面少數幾位數的系統計算性能誤差。這些基本要求, ABC FORTH 都一一實現了,而可以迅速的操作性能,則是 FORTRAN 程式語言所無法辦到的。

微分方程的數值分析解法,其實強調的重點是在試出最恰當的每次步進間隔值,如本文範例程式中的 H ,應該取多少才恰當?取的太大了,逐點推進演算的結果就會算不準。取的太小了,每次可以推進的距離就很小,要算很久、很多點後才有結果。這個現象就如同使用離散(Discrete)表示法,以可隨時間變化的加速度來計算下一個速度值,離散時刻的時間分割至很小時,解答會較準,但要推進很多點後才會有最後希望知道的速度答案。一次就想算得許久時刻後的速度,答案就會很離譜,表示時間間隔值取的太大了,根本不能這樣算。如果重點是這樣,那麼容易操作的數學計算系統就會很有用,可以快速修改、調整、獲得恰當的步進間隔值結果。 ABC FORTH 當然比 FORTRAN 好用多了,這就是我為什麼創作 ABC FORTH 數學計算系統的主因,它可以使運用電腦解決問題的習慣完全改觀。能夠執行數學計算的系統不算甚麼,擁有即時性操作效果的系統就非等閒之輩了。

我以這種方式貢獻給大家的 ABC FORTH 數學計算系統,能使此前出版過的所有數值分析教科書永遠有用,永遠不必被淘汰,因為應用數學的理論部份,是大約 200 年不會過時的,書中的實務範例程式,則可以經由 ABC FORTH 數學計算系統輕易再生,這樣做等於是『化腐朽為神奇』,講求社會道德,減少隨便廢棄有用物質而造福全人類。

我不想浪費時間在電腦編輯系統中,尋找漂亮的數學表示符號編寫這篇文章,所以一些數學表示式,就編寫成意義相同,外觀卻有一點不尋常的格式。

原 FORTRAN 程式去除刊頭文字說明及無用的 FORMAT 內容後,重新打字輸入於此處,數據及執行結果則不再編列於此。改寫完成的 ABC FORTH 對應程式,及其中一套數據輸入後的執行結果,則用電腦系統的可選擇性複製、轉換環境後再貼上的功能,轉置到此處,這是一篇實用教材。


 
   
c     APPLIED NUMERICAL METHODS, EXAMPLE 6.3
c     ELECTRICAL TRANSIENTS USING THE RUNGE-KUTTA METHOD
      IMPLICIT REAL*8( A-H, O-Z)
      INTEGER RUNGE
      DIMMENSION F(2), V(2), IMAGE(1500)
c     …..READ AND PRINT DATA
   1  READ (5,100) R, HL, C, VZERO, H, TMAX, IFREQ, IFPLOT
      WRITE (6,200) R, HL, C, VZERO, H, TMAX, IFREQ, IFPLOT
c     …..INITIALIZE T, V(1), V(2) AND ICOUNT
      T = 0.0
      V(1) = VZERO
      V(2) = 0.0
      ICOUNT = 0
c     …..COMPUTE ALPHSQ AND ALPHA, PRINT HEADINGS
      ALPHSQ = 1./(C*HL) – R* R /(4.0*HL*HL)
      ALPHA = DSQRT (DABX(ALPHSQ))
      RO2L = R/(2.*HL)
      IF ( IFPLOT .NE. 1 ) GO TO 3
        CALL PLOT1( 0, J, 11, 6, 19 )
        CALL PLOT2( IMAGE, TMAX, 0., DABS(VZERO), -DABS(VZERO) )
    3 WRITE (6,201)
c      …..IS CIRCUIT OVER-, CRITICALLY-, OR UNDER-DAMPED
c      …..COMPUTE ANALYTICAL SOLUTION, PRINT AND PLOT
    4  IF (ALPHSQ) 5, 6, 7
    5  TRUV =VZERO*DEXP(-RO2L*T)*((1.+RO2L/ALPHA)*
    1 DEXP(ALPHA*T)+(1.-RO2L/ALPFA)*DEXP(-ALPHA*T))/2.0
      GO TO 8
    6 TRUV =VZERO*DEXP(-RO2L*T)*(1.+RO2L*T)
      GO TO 8
    7 TRUV=VZERO*DEXP(-RO2L*T)*DCOS(ALPHA*T-DATAN(RO2L/ALP
    1 HA))/(ALPHA*DSQRT(C*HL))
    8 IF ( IFPLOT .NE. 1 ) GO TO 10
      CALL PLOT3( 1H*, T, V(1), 1, 8)
   10 WRITE (6,202) T, V(1), TRUV, V(2)
c     …..CALL ON THE FOURTH-ORDER RUNGE-KUTTA FUNCTION
   11 K = RUNGE(2,V, F, T, H )
c     …..WHENEVER K=1, COMPUTE DERIVATIVE VALUES
      IF ( K .NE. 1 ) GO TO 13
      F(1)=V(2)
      F(2)=-R*V(2)/HL –V(1)/(HL*C)
      GO TO 11
c    …..IF T EXCEEDS TMAX, TERMINATE INTEGRATION
   13 IF ( T .LE. TMAX ) GO TO 16
      IF ( IFPLOT .NE. 1 ) GO TO 1
      WRITE ( 6,203)
      CALL PLOT4( 7, 7HVOLTAGE )
      WRITE ( 6,204)
      GO TO 1
   16 ICOUNT=ICOUNT+1
c     …..PRINT RESULTS OR CALL DIRECTLY ON RUNGE
      IF ( ICOUNT .NE. IFREQ ) GO TO 11
      ICOUNT = 0
      GO TO 4
c     …..FORMATS FOR INPUT AND OUTPUT STATEMENTS
100   FORMAT ( …………..)
200   FORMAT (……………)
201   FORMAT (…全略……)
202   FORMAT (……………)
203   FORMAT (……………)
204   FORMAT (……………)
      END

FUNCTION RUNGE( N, Y, F, X, H )
IMPLICIT REAL*8(A-H, O-Z)
REAL*8 Y, F, X, H
INTEGER RUNGE
DIMENSION PHI(50), SAVEY(50), Y(N), F(N)
DATA   M/0/
M=M+1
GO TO (1,2,3,4,5), M
c     …..PASS 1
   1  RUNGE=1
      RETURN
c     …..PASS 2
   2  DO 22 J = 1 , N
      SAVEY(J)=Y(J)
      PHI(J)=F(J)
    22 Y(J)=SAVEY(J)+0.5*H*F(J)
X=X+0.5*H
RUNGE=1
RETURN
c     …..PASS 3
   3  DO 33 J = 1, N
      PHI(J)=PHI(J)+2.0*F(J)
    33 Y(J)=SAVEY(J)+0.5*H*F(J)
RUNGE=1
RETURN
c     …..PASS 4
   4  DO 44 J=1, N
      PHI(J)=PHI(J)+2.0*F(J)
    44 Y(J)=SAVEY(J)+H*F(J)
X=X+0.5*H
RUNGE=1
RUTURN
c     …..PASS 5
   5  DO 55 J = 1, N
  55  Y(J)=SAVEY(J)+(PHI(J)+F(J))*H/6.0
      M=0
      RUNGE=0
      RETURN
      END

改寫完成的 ABC FORTH 完整程式及十群範例輸入數據如下:

\ Runge-Kutta Method for ODE

INTEGER M     INTEGER J     INTEGER RUNGE
INTEGER N
10 ARRAY Y    10 ARRAY F
REAL X        REAL H
50 ARRAY PHI  50 ARRAY SAVEY

: F(RK4)     BASIC
10 REM ***F(RUNGE) = FUNCTION RUNGE( N, Y, F, X, H )
20 LET M = M + 1
30 IF M = 1 THEN 60
40 GOTO 80
50 REM ***PASS 1
60 LET RUNGE = 1
70 GOTO 9999
80 IF M = 2 THEN 110
90 GOTO 180
100 REM ***PASS 2
110 FOR J = 1 TO N
120 LET { SAVEY ( J ) = Y ( J ) }
125 LET { PHI ( J ) = F ( J ) }
130 LET { Y ( J ) = SAVEY ( J ) + 0.5 * H * F ( J ) }
140 NEXT J
150 LET { X = X + 0.5 * H }
160 LET RUNGE = 1
170 GOTO 9999
180 IF M = 3 THEN 210
190 GOTO 270
200 REM ***PASS 3
210 FOR J = 1 TO N
220 LET { PHI ( J ) = PHI ( J ) + 2.0 * F ( J ) }
230 LET { Y ( J ) = SAVEY ( J ) + 0.5 * H * F ( J ) }
240 NEXT J
250 LET RUNGE = 1
260 GOTO 9999
270 IF M = 4 THEN 300
280 GOTO 370
290 REM ***PASS 4
300 FOR J = 1 TO N
310 LET { PHI ( J ) = PHI ( J ) + 2.0 * F ( J ) }
320 LET { Y ( J ) = SAVEY ( J ) + H * F ( J ) }
330 NEXT J
340 LET { X = X + 0.5 * H }
350 LET RUNGE = 1
360 GOTO 9999
370 IF M = 5 THEN 400
380 GOTO 430
390 REM ***PASS 5
400 FOR J = 1 TO N
410 LET { Y ( J ) = SAVEY ( J ) + ( PHI ( J ) + F ( J ) ) * H / 6.0 }
420 NEXT J
430 LET M = 0
440 LET RUNGE = 0
9999 END ;

INTEGER K       INTEGER ICOUNT常微方程式之 Runge-Kutta 解法
INTEGER IFREQ   INTEGER IFPLOT
REAL RT1   REAL RT2      REAL RT3
REAL R     REAL HL       REAL C         REAL VZERO
REAL RO2L  REAL ALPHA   REAL ALPHSQ
REAL TRUY  REAL TMAX

: GROUP1
  {{ R = 100.00  }} {{ HL    =  0.50 }}
  {{ C = 2.0E-6  }} {{ VZERO = 10.00 }}
  {{ H = 0.00001 }} {{ TMAX  = 0.025 }}
  [[ IFREQ =  25 ]] [[ IFPLOT =   0  ]]
;
: GROUP2
  {{ R =    0.00 }} {{ HL    =  0.50 }}
  {{ C =  2.0E-6 }} {{ VZERO =  10.0 }}
  {{ H = 0.00010 }} {{ TMAX  = 0.020 }}
  [[ IFREQ =  10 ]] [[ IFPLOT =    0 ]]
;
: GROUP3
  {{ R = 1000.00 }} {{ HL    =  0.50 }}
  {{ C =  2.0E-6 }} {{ VZERO =  10.0 }}
  {{ H = 0.00010 }} {{ TMAX  = 0.020 }}
  [[ IFREQ =  10 ]] [[ IFPLOT =    0 ]]
;
: GROUP4
  {{ R = 1500.00 }} {{ HL    =  0.50 }}
  {{ C =  2.0E-6 }} {{ VZERO =  10.0 }}
  {{ H = 0.00010 }} {{ TMAX  = 0.020 }}
  [[ IFREQ =  10 ]] [[ IFPLOT =    0 ]]
;
: GROUP5
  {{ R =  100.00 }} {{ HL    =  0.50 }}
  {{ C =  2.0E-6 }} {{ VZERO =  10.0 }}
  {{ H = 0.00001 }} {{ TMAX  = 0.020 }}
  [[ IFREQ = 100 ]] [[ IFPLOT =    0 ]]
;
: GROUP6
  {{ R =  100.00 }} {{ HL    =  0.50 }}
  {{ C =  2.0E-6 }} {{ VZERO =  10.0 }}
  {{ H = 0.00010 }} {{ TMAX  = 0.020 }}
  [[ IFREQ =  10 ]] [[ IFPLOT =    0 ]]
;
: GROUP7
  {{ R =  100.00 }} {{ HL    =  0.50 }}
  {{ C =  2.0E-6 }} {{ VZERO =  10.0 }}
  {{ H = 0.00100 }} {{ TMAX  = 0.020 }}
  [[ IFREQ =   1 ]] [[ IFPLOT =    0 ]]
;
: GROUP8
  {{ R =  100.00 }} {{ HL    =  0.50 }}
  {{ C =  2.0E-6 }} {{ VZERO =  10.0 }}
  {{ H = 0.00200 }} {{ TMAX  = 0.020 }}
  [[ IFREQ =   1 ]] [[ IFPLOT  =   0 ]]
;
: GROUP9
  {{ R =  100.00 }} {{ HL    =  0.50 }}
  {{ C =  2.0E-6 }} {{ VZERO =  10.0 }}
  {{ H = 0.00500 }} {{ TMAX  = 0.020 }}
  [[ IFREQ =   1 ]] [[ IFPLOT =    0 ]]
;
: GROUP10
  {{ R =  100.00 }} {{ HL    =  0.50 }}
  {{ C =  2.0E-6 }} {{ VZERO =  10.0 }}
  {{ H = 0.01000 }} {{ TMAX  = 0.020 }}
  [[ IFREQ =   1 ]] [[ IFPLOT =    0 ]]
;

: PRINT-INPUT-DATA   BASIC
10 REM ***PRINT DATA
20 PRINT "      R = " ; { R }
30 PRINT "     HL = " ; { HL }
40 PRINT "      C = " ; { C }
50 PRINT " VZERO = " ; { VZERO }
60 PRINT "      H = " ; { H }
70 PRINT "  TMAX = " ; { TMAX }
80 PRINT "  IFREQ = " , IFREQ
90 PRINT " IFPLOT = " , IFPLOT
100 END ;

: INIT    BASIC
10 REM ***INITIALIZE X, Y(1), Y(2), AND ICOUNT
20 LET { X = 0 }
30 LET { Y ( 1 ) = VZERO }
40 LET { Y ( 2 ) = 0.0 }
50 LET ICOUNT = 0
60 LET N = 2 
70 END ;

: WRITE(6,201)
\ PRINT HEADINGS
  CR 10 SPACES ." X "      10 SPACES ." CALC. Y "
     10 SPACES ." TRUE Y " 10 SPACES ." CALC. Y' " CR
;

: COMPUTE-CONSTANT   BASIC
10 REM ***COMPUTE ALPHSQ AND ALPHA, PRINT HEADINGS
20 LET { ALPHSQ = 1. / ( C * HL ) - R * R / ( 4.0 * HL * HL ) }
30 LET { ALPHA = SQRT ( ABS ( ALPHSQ ) ) }
40 LET { RO2L = R / ( 2. * HL ) }
50 IF IFPLOT <> 1 THEN 80
60 REM ***CALL PLOT1
70 REM ***CALL PLOT2
80 RUN WRITE(6,201)
90 END ;

: WRITE(6,202)   BASIC
10 REM ***PRINT SOLUTION
20 PRINT { X , Y ( 1 ) , TRUY , Y ( 2 ) }
30 END ;

: DAMPED   BASIC
10 REM ***IS CIRCUIT OVER-, CRITICALLY-, OR UNDER-DAMPED
20 REM ***COMPUTE ANALYTICAL SOLUTION, PRINT OR PLOT
30 IF { ALPHSQ < 0 } THEN 50
40 GOTO 100
50 LET { RT1 = ( 1. + RO2L / ALPHA ) * EXP ( ALPHA * X ) }
60 LET { RT2 = ( 1. - RO2L / ALPHA ) * EXP ( NEGATE ( ALPHA ) * X ) }
70 LET { RT3 = ( RT1 + RT2 ) / 2.0 }
80 LET { TRUY = VZERO * EXP ( NEGATE ( RO2L ) * X ) * RT3 }
90 GOTO 170
100 IF { ALPHSQ = 0 } THEN 120
110 GOTO 140
120 LET { TRUY = VZERO * EXP ( NEGATE ( RO2L ) * X ) * ( 1. + RO2L * X ) }
130 GOTO 170
140 LET { RT1 = COS ( ALPHA * X - ATAN ( RO2L / ALPHA ) ) }
150 LET { RT2 = ALPHA * SQRT ( C * HL ) }
160 LET { TRUY = VZERO * EXP ( NEGATE ( RO2L ) * X ) * RT1 / RT2 }
170 IF IFPLOT <> 1 THEN 190
180 REM ***CALL PLOT3
190 RUN WRITE(6,202)
200 END ;

: CALL-FUNCTION-F(RK4)
  F(RK4)
;

: MAIN   BASIC	\ 執行Runge-Kutta的主要指令
10 RUN GROUP2  \ (1)輸入數據建立了十組,於此處自行選擇更換
20 RUN PRINT-INPUT-DATA
30 RUN INIT
40 RUN COMPUTE-CONSTANT
50 RUN DAMPED
60 REM ***CALL ON THE FOURTH-ORDER RUNGE-KUTTA FUNCTION
70 LET M = 0
80 RUN CALL-FUNCTION-F(RK4)
90 LET K = RUNGE
100 REM ***WHENEVER K=1, COMPUTE DERIVATIVE VALUES
110 IF RUNGE <> 1 THEN 150
120 LET { F ( 1 ) = Y ( 2 ) }
130 LET { F ( 2 ) = NEGATE ( R ) * Y ( 2 ) / HL - Y ( 1 ) / ( HL * C ) }
140 GOTO -80
150 REM *** IF X EXCEEDS TMAX, TEERMINATE INTEGRATION
160 IF { X <= TMAX } THEN 210
170 GOTO 260
\ 180 IF IFPLOT <> 1 THEN -10
\ 190 REM ***WRITE(6,203),CALL PLOT4,WRITE(6,204)
\ 200 GOTO -10
210 LET ICOUNT = ICOUNT + 1
220 REM ***PRINT RESULTS OR CALL DIRECTLY ON RUNGE
230 IF ICOUNT <> IFREQ THEN -70
240 LET ICOUNT = 0
250 GOTO -50
260 PRINT " ***Run next GROUPn by change ( 10 RUN GROUPn )*** "
270 END ;

直接操作ABC FORTH系統,執行MAIN指令,所得結果顯示如下:

MAIN
     R =     0.000000000E-1
    HL =      .5000000000
     C =     2.000000000E-6
 VZERO =    10.00000000
     H =      .0001000000
  TMAX =      .0200000000
 IFREQ =    10
IFPLOT =     0
          X              CALC. Y         TRUE Y              CALC. Y'

   0.000000000E-1      10.00000000     10.00000000          0.000000000E-1
    .0010000000         5.403029671     5.403023059     -8414.704778
    .0020000000        -4.161452687    -4.161468365     -9092.979918
    .0030000000        -9.899919391    -9.899924966     -1411.224448
    .0040000000        -6.536459532    -6.536436209      7568.001143
    .0050000000         2.836581058     2.836621855      9589.251198
    .0060000000         9.601684950     9.601702867      2794.201656
    .0070000000         7.539057071     7.539022543     -6569.818977
    .0080000000        -1.454933809    -1.455000338     -9893.586642
    .0090000000        -9.111266133    -9.111302619     -4121.250371
    .0100000000        -8.390754644    -8.390715291      5440.137662
    .0110000000          .0441656076     .0442569799     9999.894840
    .0120000000         8.438479098     8.438539587      5365.808798
    .0130000000         9.074504988     9.074467815     -4201.568624
    .0140000000         1.367486013     1.367372182     -9906.048042
    .0150000000        -7.596790229    -7.596879129     -6502.966258
    .0160000000        -9.576622425    -9.576594803      2878.902739
    .0170000000        -2.751765848    -2.751633381      9613.924740
    .0180000000         6.603046592     6.603167082      7509.961785
    .0190000000         9.887056797     9.887046182     -1498.614135
***Run next GROUPn by change ( 10 RUN GROUPn )***  ok

執行後所得結果,與原始資料內容比較,毫不遜色。