2026年8月16日 星期日

韓信點兵

韓信點兵


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


此前貼出過之百例中的第 81 例展示過一個韓信點兵的精簡程式,該程式採用暴力計算方式,只按問題直接強行計算,算到全部合乎指定條件後,得到解答。

本文中的程式則將問題建立成表格來計算,執行對答方式輸入問題,以敘述方式給出答案。

如果不能寫出不同的見解,就不該寫這篇文章,以免浪費讀者的寶貴時間。因為這是一個古老的中國算學技術,是西元前 200 年(韓信死於西元前 196 年)左右的問題,距今約 2200 年了。

中國秦朝末年,楚漢相爭,結果漢高祖劉邦打敗項羽取得天下,建立了漢朝。那時,有所謂的漢初三傑:指的就是韓信、張良、蕭河。韓信是個軍事奇才,曾經擔任軍隊的總司令,被任命為大將軍,協助漢高祖劉邦打天下,但不幸最後卻因被懷疑意圖謀反,而被蕭河及呂后(呂雉)騙入宮中,處死於長樂宮鐘室。

中國人無人不知、無人不曉『韓信點兵』的問題,卻罕有人能熟記,解這個問題的詳細理論依據,或將其學通後加以活用,或用來解出其他所有相關與類似的問題,這種情況,經過了兩千多年,甚至於一直到今天,依然如此。

據說,這個問題還曾經被納入高中的數學教材,可以想像,數學老師教起來必然辛苦,學生也學得痛苦。我不記得我在高中學習不定方程式(Indeterminate equations)時,必須學這項主題,就算學過,也早就忘了教材中曾經教過我,該如何按邏輯嚴格演繹以求得解答的詳細步驟了,反而是單一種逐步計算的方法,我終生都記得。

本文就專門只談論這種永遠記得住的解題方法,它確實就是各種方法中的一個好方法,還可以用來實現一個永遠可以存在、放諸四海而皆準的程式,要完成這樣的程式,也必須按邏輯嚴格演繹,設計出來的程式,此後才能古今中外都派得上用場。

科學月刊中現代數學名家的『韓信點兵』文章內,批評只有『答案』與『計算技巧』的堆積,無法顯現『數學的妙趣』,我百分之百同意這樣的觀點。但是,我反對為了培養『數學的妙趣』,而刻意略去能夠直接了當解得問題答案的最簡單方法。試想,如果無限多個『韓信點兵』式的問題堆積在眼前,您該怎麼辦?當精簡的『演算技巧』,與絕對需要的『答案』,您都遲遲難以獲得時,請問,您那來的『數學妙趣』?因此,我改而另覓它途,解決『韓信點兵』問題。把思考轉向電腦程式的邏輯嚴格演繹,而不是純粹數學的邏輯嚴格演繹,完成一個對談式萬用程式,包括落定美觀的排版所耗時間,大約只花兩小時,但是,『它』今後可以永遠有用。

這篇文章的目的,並不是想否定所有有關『韓信點兵』問題的理論分析教學,相反的,我仍鼓勵大家能學通以『韓信點兵』為例而安排出來的理論分析教材內容,畢竟,它相關於其他的數學學問,適合作為人人都熟悉的問題範例。

至於想實際解出這個問題的答案時,我個人覺得,現今,應該用電腦程式來解,而且,要將程式設計成對談式的萬用程式,至少,讓這個問題今後都能如此方便的解得答案。原因在於,一方面電腦幾乎是當今人人生活上必用的工具,那麼,電腦程式解題的方法,只要能合理解得正確的答案,就該認同這個方法,沒有理由硬要排除它。另一方面,則是現行電腦的執行速度與友善的操作環境,已經發展得相當完善了,適合作為解決這種問題的工具。我將電腦程式設定成逐步計算到達十萬次以上時,就當作可以落定題目為無解,使用已經 20 幾年高齡的電腦,也不過耗時僅約一秒。為何不用電腦程式來解問題?我堅決反對拒教電腦解題技術,不教就違反時代趨勢。

台灣發行的『科學月刊』,算得上是一本優良的普及性科學雜誌,我也愛讀,雜誌內容曾經出現過許多次談論有關『韓信點兵』的討論文章。

來自四面八方的數學專家,與各大學的許多教授,都曾為『韓信點兵』問題,寫過精闢的解題方法分析文章。如果您對求解此一問題之純粹理論性的分析有興趣,可以在網上搜索出不下百篇的文章來,國際上將這種問題命名為『中國剩餘定理』(Chinese Remainder Theorem)。為了要完成本文,我做過這樣的工作,快速瀏覽這些文章後,只有一種感覺,實在不想、也根本無法記下所有的邏輯推演步驟,今生再度碰到『韓信點兵』問題時,我還是只會逐步計算,使用規律增量式的逐個試算,最後絕對能得到正確的答案。

我都已經 75 歲了,記那些解題時必須要用到的定理、定律,與專門只用於解這種問題時,才需要使用的特別符號,有必要嗎?今天記了,大概明天就忘了,何苦來哉?

為『韓信點兵』問題而公開發表過的那些高明分析文章,仔細讀完之後,對我而言,充其量也只能讓我感到各文章作者言之有理,對必須解決實際問題的最基本要求,則實在幫助不大,更遑論憑此而能衍生出更高深的知識或技術了。換句話說,那些文章該看,至於能不能因此而領悟出連貫性知識或技術?那就得看個人對此一問題的進一步修行意願了,結果絕對因人而異,而願意前行者少。

最原始的『韓信點兵』問題,節錄如下:

兵不知其數,三三數之剩二,五五數之剩三,七七數之剩二,最少兵數應該是多少?

問題可以改寫成現代人使用之數學符號表示的聯立方程式,列示如下:

X = 3 * Q(1) + 2
X = 5 * Q(2) + 3
X = 7 * Q(3) + 2

這是一個只有三個已知關係的數學聯立方程式,卻要求解四個未知變數X、Q(1)、Q(2)、Q(3)。因為還差一個已知數學關係式,所以使這種問題被歸納入不定方程式的範疇。解答必須為整數的隱含要求,是代表兵士不得為半個人,或 3.1416 個人。

為了本文隨後表示上的方便,此處刻意引用『科學月刊』中,數學專家所使用的更精簡表示符號,以 S(N|R) 來表示問題,它代表 S 以 N 除之餘 R ,S 代表這種所有數字的集合,上列三個式子因此而得以進一步簡化表示成:

S(3|2) , S(5|3) , S(7|2)

直接逐步演算的方法為:

(1) 先找出條件中最大除數的那一項條件,以此數作為整個演算的基底數字。
在上列原始問題中為 7
(2) 設定一個計數器,令其從 1 開始計數,然後算出第一個可能符合條件的數字。
在上例中為 7*1+2=9
(3) 用(2)中得到的數字,去核算並判斷是否亦符合其他條件。
在上例中, 9/3=3 餘 0,9/5=1 餘 4 ,結果與原已知條件均不符合
(4) 回到(2)中將計數器值加 1 ,繼續(3)的核算,直到滿足所有條件為止,便可得到一個首先能夠獲得的答案。
在上例中,當計數器為 3 時, 7*3+2=23,23/3=7 餘 2 , 23/5=4 餘 3,符合要求,因此, 23 就是一個首先獲得的答案。

故事書上說,漢高祖劉邦聽不懂韓信的兵數描述,轉問張良,張良卻回話說:『兵數無法算,不可數。』

這樣的回答不對,方法就像上述這麼簡單,算 3 次後就可以得到一個核心基本根據數字,數學專業術語稱作『特解』,接下來要形成『通解』時,答案就是特解加上任意一個正整數乘上所有已知條件中的除數,在上例中為:

23 + N * ( 3 * 5 * 7 ) = 23 + N * 105 其中 N = 0, 1, 2, .....

這就是全部求解『韓信點兵』問題的逐步計算法,我相信,任何人看過上述解題方法的敘述之後,都能終身記得,都能終身使用,我的程式也就是根據這麼簡單的方法設計而成的。

通常我們求解一個數學問題時,首先要確定問題的答案是否『存在』(Exist)?上例中求得的23,表示答案確實存在,它就可以被確定是問題的一個特別解答,簡稱『特解』(Particular solution)。接下來要確定問題的答案是否為『唯一』(Unique)?經過仔細研究後,我們發現這種問題的解答不是唯一的,其特解23加上所有除數相乘後再乘上任意一個正整數,也都是問題的答案,因此,我們必須將所有的解答以適當的數學式子表示出來,以形成這個問題全部的通盤解答,簡稱『通解』(General solution)。數學理論中解答的『存在』與『唯一』性質,對應到解答的『特解』與『通解』,這個『韓信點兵』問題的通解,僅只是由簡單的乘法來形成,沒有其他任何技巧,因此,本文只討論問題的特解,程式中也不計算出簡單的通解,特此聲明。

由此看來,下一次考試碰到這樣的問題時,別再依靠那些無法終身記得的分析式演繹算法了,我能確定大多數人,僅能暫時性的理解分析演繹法,如果背下方法,考完就忘了,那又何須浪費時間去背記?將這些用來理解與背記所需的時間,改用來思考解決其他的學習問題,可能比較有意義。通常,上述計數器只須計數幾次,答案就可以獲得,因為考題所給的除數都不會太大,經常是個位數,已知條件也不會太多,一般就只有二或三個,取一張計算紙,列個表,快速心算後在每一列後面做個記號,很快就會有結果,如果嫌計算冗長,影響求解其他問題,那麼,這一題留到最後才解。

平時呢?您也不必怕我這樣強調性的教您如此求解問題會害了您,就根據上述逐步演算法,我寫成了永遠都能使用的對談式萬用程式,列示於本文內,使用時,可以在電腦開機後,只操作滑鼠點選三、四次,就有一個我設計而命名為 MAIN 的指令可以直接使用。好好的使用,它就能幫助您一天內解出幾千幾百個『韓信點兵』問題。碰到子女問您同樣的問題時,就算您不懂韓信如何點兵,這個對談程式會協助您,給予您滿意的答案,讓全家人皆大歡喜,然後,您就有信心告訴子女,應該好好學 FORTH 程式語言, FORTH 能設計出所有的程式。

我原本全部使用中文設計出這個程式,完成之後,考慮本文可以供給全世界的人參考使用,於是又將一般程式部份改成了英文,如此一來,也能供給慣於使用其他程式語言者,參考後模仿設計。

我瀏覽過網路,搜索能解『韓信點兵』問題的實際可用程式,大部份都是用 C 或 Python 程式語言寫的,由於 C 不方便用來設計立即對談式(Real time interactive)程式,因此,那些程式都只能解單一個韓信 2200 年前提出來的最原始問題,我用心算都可以比發展那樣的程式還快速的得到答案,所以那些程式沒有價值。

時代不同了,現代電腦的記憶體用量與執行速度,在用來解決這種問題而必須設計程式時,已經不用強調要節省記憶體空間與程式執行效率的問題。相反的,為了讓大多數人看過程式之後,能夠一目了然,我將程式設計成不在乎多執行了一些步驟,要用到的變數宣告量,也不用斤斤計較到要強調共用而節省。程式可執行出合理範圍內的答案,韓信不會有億萬大軍,解放軍再多,也只能論及幾百萬,這是一個兼顧了實際情況的程式。

採用對談式程式語言(如 FORTH )來設計這種程式,比採用編譯式程式語言(如 C )要好,使用方便且具彈性。我的程式中雖然暫時只規劃了可以輸入最多十組已知條件,要變通時,只需修改這個設定,但當已知條件多於十個以上時,程式改成輸入數據預置於檔案程式內的方式會比較好,可以防止一鍵敲錯而滿盤皆輸必須重來的困擾。這個程式是透通的, FORTH 是必須使用模組化格式設計程式的語言,想改寫程式,簡單之至,這就是 FORTH 。

七十年前,我們唸小學高年級時,每天幾乎都要習作 50 題當年『武明算術』內的習題,我不曾不交作業,學習方面只是認真但不聰明,可是這些學習方式,影響了我的一生,這樣的學習過程,可能是決定了我能否快速設計出電腦程式來解決問題的關鍵因素,我的小學老師是內壢國民小學的范金櫻老師,能有現在的能力,該感謝我的老師。

今天,此處列示的這個有用程式,它不僅只是代表了我寫成一個實用的程式,而是代表了我設計出一套永遠都容易建立的可對談式數學計算系統,然後讓大家可以很方便的設計程式,來解決所有的數學計算問題。截至目前為止,全世界尚無人能比,而這個系統還要發展。系統並非完全由我個人隻身獨立發展而成,我善用組合能力,組合了許多名家的長處來創造出系統,也因此而令其性能傑出,也因此而令系統隨時都還能繼續發展。

我出身軍人世家,自己也是被國軍淘汰下來的職業軍人,俗話說:『好鐵不打釘,好漢不當兵』,這句俗話是錯的,全世界不是軍人的人,此前還沒有人有能力,像我這個出身為軍人的人,設計出這麼方便且能夠處理許多問題的 ABC FORTH 數學計算系統,而我卻曾經是個『兵』。軍中的同袍,也請不要妄自菲薄,平時就該努力充實自己,設法接受我的這個 ABC FORTH 數學計算系統。戰時,軍方需要快速且大量的軍事作業研究(Operation research)來提供制敵的先機,其中許多問題需要大量的數學計算。目前,全世界還找不到像 ABC FORTH 那麼方便的系統,可以立即執行,可以對談式操作,專門用來處理數學計算,能夠快速處理這種『韓信點兵』式的問題。善用這樣的系統,在技術上就可以勝過一個韓信總司令,我不會像韓信那樣,將秘笈祖傳起來,下列就列示一個祕笈。

接下來,我先以前述『科學月刊』中最佳的問題表示符號,列示十二個曾經被提出來當範例的『韓信點兵』典型問題,供作程式測試之用,接著列示我所設計的程式。最後,我將程式載入 ABC FORTH 系統,直接操作系統,求解這十二個問題,執行的結果當然都是正確的,全部顯示在畫面上。再操作滑鼠,選定執行結果所產生的整個畫面,令其反白、複製、再轉貼入此文,讓讀者能夠完完整整的看到整個結果。

如果您願意實際體會執行這個程式後,快速得到正確答案的感覺,所呈現出來的現象將會是:每當您輸入了 MAIN 指令後,就會有一個滿意的終結。不想再執行 MAIN 指令了,也可以改執行 CHECK 指令,去看一下程式內的資料內容,或者就輸入 SEE MAIN 兩個指令,看系統把我設計的程式編成甚麼模樣了?顯示出來的這些現象,係 FORTH 程式語言一旦執行起來之後,就會顯現作業系統的性能所致。這是 Win32Forth 系統的作者 Tom Zimmer ,在網路論壇上給全世界 FORTH 使用者的善意建議,我提供了全套應用實例,您請自己體會。

請注意問題(6)無解,程式執行後就顯示無解。
問題(1)就是歷史上韓信提出來的第一個問題,它再簡單,程式也要能解。
問題(9)的答案比較特別,是除數全乘起來以後再除以2,程式也毫不含糊的快速顯示正確的執行結果。
現任學校的老師,如果想要隨便出幾個題目來考學生,利用這個程式,隨便輸入一些組合條件,就能先行得到答案,這些條件,就能當作別人從未出過的考題來考學生。
學生只要肯學 FORTH ,就能利用這個程式來對付老師的刁難。
一天之內,您想解出成千上萬個這種問題的答案,怎麼沒有可能?
總而言之,這個程式是方便而萬用的。
我則能擔保,永遠都有能夠執行這個程式的系統存在世上。


●十二個典型的問題為:

(1) S(3|2) , S(5|3) , S(7|2)
(2) S(7|1) , S(8|2) , S(9|3)
(3) S(11|3) , S(12|2) , S(13|1)
(4) S(2|1) , S(5|2) , S(7|3) , S(9|4)
(5) S(5|0) , S(6|1)
(6) S(12|5) , S(18|13)
(7) S(12|5) , S(18|17)
(8) S(15|7) , S(21|13) , S(10|2)
(9) S(11|1) , S(13|2) , S(15|3) , S(17|4) , S(19|5)
(10) S(3|1) , S(5|2) , S(7|4)
(11) S(8|1) , S(7|1) , S(5|2)
(12) S(7|3) , S(11|5) , S(13|8)

●程式及執行結果列示如下:


 

\ 韓信點兵 Chinese Remainder Theorem
\ 作者:曾慶潭 於紐西蘭 
\ 版權所有,標示版權,便歡迎使用。
\ Copyright 2011-02-16 Ching-Tang Tseng	
\ Permission is granted by the author to use this software for any application
\ provided this copyright notice is preserved.

10 2 整數矩陣 TABLE    \ 編制表

整數變數 NC          \ 條件量Number of Conditions
整數變數 TOTAL       \ 總兵數
整數變數 COUNTS      \ 點兵次數
整數變數 MAXI        \ 編制為最多班兵之指標Max divisor Index
整數變數 RMOD        \ 點兵後之餘兵數Remainder after MOD
整數變數 RF          \ 點兵後之餘兵數比對旗號Remainder checking Flag
整數變數 I           \ 循環指標1
整數變數 J           \ 循環指標2

: 歸零 中文程式
10 FOR J = 1 TO 2
20 FOR I = 1 TO 10
30 LET TABLE ( I J ) = 0
40 NEXT I
50 NEXT J
60 LET NC = 0
70 LET TOTAL = 0
80 LET COUNTS = 0
90 LET MAXI = 0
100 END 
;

: 對談式輸入 中文程式
10 PRINT " 請輸入有幾個韓信點兵問題的已知條件  "
20 INPUTI NC
30 PRINT " 下列操作,將要求您每次以兩個分開的整數方式輸入 " ; NC ; " 組條件。 "
40 PRINT " 條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  "
50 FOR I = 1 TO NC
60 PRINT " 請輸入第 " ; I ; " 組條件 "
70 INPUTI TABLE ( I 1 ) , TABLE ( I 2 )
80 NEXT I
90 END
;

: 找出最多班兵之指標 中文程式
10 LET MAXI = 1
20 FOR I = 1 TO NC
30 IF TABLE ( I 1 ) > TABLE ( MAXI 1 ) THEN 50
40 GOTO 60
50 LET MAXI = I
60 NEXT I
70 END
;

: 點兵 中文程式
10 LET COUNTS = COUNTS + 1
20 LET RF = 0
30 LET TOTAL = TABLE ( MAXI 1 ) * COUNTS + TABLE ( MAXI 2 )
40 FOR I = 1 TO NC
50 LET RMOD = TOTAL MOD TABLE ( I 1 )
60 IF RMOD = TABLE ( I 2 ) THEN 80
70 LET RF = RF + 1
80 NEXT I
90 IF COUNTS > 100000 THEN 130
100 IF RF <> 0 THEN -10
110 PRINT " 點兵點了 " ; COUNTS ; " 次,得到的答案為 " ; TOTAL
120 GOTO 140
130 PRINT " 點兵次數超過十萬次,還點不出答案,太不合理,故此題無解! "
140 RUN CR CR
150 END
;

: MAIN 中文程式
10 執行 歸零
20 執行 對談式輸入
30 執行 找出最多班兵之指標
40 執行 點兵
50 結束
;

: CHECK BASIC
10 FOR I = 1 TO 2
20 FOR J = 1 TO 10
30 PRINT " TABLE ( " ; J ; I ; " ) = " ; TABLE ( J I )
40 NEXT J
50 NEXT I
60 PRINT MAXI , TOTAL , COUNTS
70 END
;

●程式執行後顯示結果如下:

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 3
下列操作,將要求您每次以兩個分開的整數方式輸入 3 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 3 2
請輸入第 2 組條件 ? 5 3
請輸入第 3 組條件 ? 7 2
點兵點了 3 次,得到的答案為 23  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 3
下列操作,將要求您每次以兩個分開的整數方式輸入 3 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 7 1
請輸入第 2 組條件 ? 8 2
請輸入第 3 組條件 ? 9 3
點兵點了 55 次,得到的答案為 498  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 3
下列操作,將要求您每次以兩個分開的整數方式輸入 3 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 11 3
請輸入第 2 組條件 ? 12 2
請輸入第 3 組條件 ? 13 1
點兵點了 1 次,得到的答案為 14 

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 4
下列操作,將要求您每次以兩個分開的整數方式輸入 4 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 2 1
請輸入第 2 組條件 ? 5 2
請輸入第 3 組條件 ? 7 3
請輸入第 4 組條件 ? 9 4
點兵點了 17 次,得到的答案為 157  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 2
下列操作,將要求您每次以兩個分開的整數方式輸入 2 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 5 0
請輸入第 2 組條件 ? 6 1
點兵點了 4 次,得到的答案為 25  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 2
下列操作,將要求您每次以兩個分開的整數方式輸入 2 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 12 5
請輸入第 2 組條件 ? 18 13
點兵次數超過十萬次,還點不出答案,太不合理,故此題無解!  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 2
下列操作,將要求您每次以兩個分開的整數方式輸入 2 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 12 5
請輸入第 2 組條件 ? 18 17
點兵點了 2 次,得到的答案為 53  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 3
下列操作,將要求您每次以兩個分開的整數方式輸入 3 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 15 7
請輸入第 2 組條件 ? 21 13
請輸入第 3 組條件 ? 10 2
點兵點了 9 次,得到的答案為 202  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 5
下列操作,將要求您每次以兩個分開的整數方式輸入 5 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 11 1
請輸入第 2 組條件 ? 13 2
請輸入第 3 組條件 ? 15 3
請輸入第 4 組條件 ? 17 4
請輸入第 5 組條件 ? 19 5
點兵點了 18232 次,得到的答案為 346413  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 3
下列操作,將要求您每次以兩個分開的整數方式輸入 3 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 3 1
請輸入第 2 組條件 ? 5 2
請輸入第 3 組條件 ? 7 4
點兵點了 9 次,得到的答案為 67  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 3
下列操作,將要求您每次以兩個分開的整數方式輸入 3 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 8 1
請輸入第 2 組條件 ? 7 1
請輸入第 3 組條件 ? 5 2
點兵點了 7 次,得到的答案為 57  

ok
MAIN 
請輸入有幾個韓信點兵問題的已知條件  ? 3
下列操作,將要求您每次以兩個分開的整數方式輸入 3 組條件。 
條件輸入格式為:每一班有幾人在前,點完兵的剩餘人數在後,例如 10 2  
請輸入第 1 組條件 ? 7 3
請輸入第 2 組條件 ? 11 5
請輸入第 3 組條件 ? 13 8
點兵點了 26 次,得到的答案為 346  

ok

2026年8月2日 星期日

巧然天成的 RUN 指令

巧然天成的 RUN 指令


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


實踐確實是檢驗真理的唯一標準,真正親自動手做過事情的人,才有資格講這句話,能講出這句話的人,也才能體會出真理的可貴。我是以整合許多名家作品的方式,設計出 ABC FORTH 數學計算系統,憑心而論,名家作品中的許多伏筆,均非淺顯而易見,設計當初,我自己並不完全知道系統竟然另外擁有許多性能,這樣的問題,唯有依靠實踐來檢驗,本文討論一些這種特性。

這個系統擁有遠大的前程,充滿著無限的發展希望,就如同 FORTH 程式語言可以無限制成長的本質一樣。但其意義並非單純的只是指令名稱可以無限的增加,也不是發展到可以直接應用於處理問題後就此作罷,而是顯現在系統無窮的性能增建能力上。這種吸引人的特質,經常會令我只顧勇往直前添加新的設計,不顧驗證已經完成的成果;只想拼命的增添系統性能,無暇管它到底能做甚麼?

如果仔細回顧我所參考過的名家設計,確實能夠體會出許多可圈可點的名家技術,但是,如果只是照抄這些技術,缺乏自己的組織構想,最後必然難成氣候,在我設計的系統中,可舉出來的這種例子很多。 ABC FORTH 數學計算系統內,由 FORTH 轉進 BASIC 式環境後,其中一個性能特異的 RUN 指令,就是一個最典型的例子。

我設計 ABC FORTH 系統時,最原始的根據是莫查理(Charles H. Moore)於 1981 年發表的論文,裴麥克(Michael Perry)隨後將其改寫成 fig-FORTH 的版本。此後,因為只須照抄,我們便能很快的將同樣設計轉進了 F83 系統,繼續維持它的存在。

翻閱這些過去的舊記錄,很容易看得出來,幾位名家都只將 RUN 指令,當作 BASIC 程式語言中,最原始定義的意義來設計。那種 RUN 指令,只能讓單一個 BASIC 程式被系統執行,與我所設計的 RUN 指令不同,我的 RUN 指令,允許無限個 BASIC 程式可以被系統執行。

因為,當時,大家只想驗證出 FORTH 很容易設計出 BASIC ,確實也辦到了,但沒有人想到要根據 RUN 指令的特性來改善系統性能。

近代 FORTH 大型系統中,健全的浮點數計算能力,以及由作業系統自然融入 FORTH 系統的中文顯示功能,是兩件吸引我選擇這個時機,在 FORTH 系統中重現 BASIC 功能的主要因素,其他大型 FORTH 系統優秀的特點都在其次。

2008 年,我在 Win32Forth 系統中完成加建 BASIC 功能的初期,並不看好這樣的設計。道理無他, 1964 年發明的 BASIC 舊觀念並不吸引人,舊觀念還有許多長期被人攻擊的缺點,例如: BASIC 中的 GOTO 指令,會令龐大的程式,形成麵條式的結構,自認為是電腦專家的人,就拿這樣的論點來嘲笑 BASIC 。我自己從不這樣批評 BASIC ,相反的,還特別鍾愛 GOTO 這種指令,道理無他,一切電腦軟體的基礎 -- 組合語言中,凡會跳躍分支的 jump 指令,都與 GOTO 相當。因此,無 GOTO 何來其他所有的程式語言?講句不客氣的話,結構化程式語言中,想添加能讓系統不出亂子的 GOTO 指令,根本很難設計,排斥 GOTO 的專家,是不是酸葡萄心理?確實難說。要不然,請以實踐檢驗真理,檢驗完了,大家也可以不用,以尊重您高尚的論調。

我常認為,自封為專家的人,都應該謹言慎行,他們的一舉一動,對社會影響重大,性能非凡的 GOTO 指令就是這樣被毀掉的。但是,請仔細想想看,多少人過去就用 GOTO 完成了多少偉大的事情? GOTO 對整個社會總的貢獻,絕對比任何一位自以為高尚的電腦專家要來得多多, GOTO 何辜?

為了這個 GOTO ,我長期思考對應之策,因此,系統設計完成之後,足足有半年時間,我並不想對任何人介紹我所設計出來的系統。思考的問題,就是如何解決被批評為『麵條式程式』?的問題,而且設定了自己的打算,如果解決不了,就不要推出自己的設計,因為歷史已經淘汰了傳統的 BASIC 。

最後,自己私下決定,經由 RUN 指令來代勞,改變它的特性,而且解決辦法精簡之至,僅只是大膽起用一個從不被列入作為標準指令,卻是每一個 FORTH 系統內必定都有的天王指令『INTERPRET』。此一自創附加技術,是一種巧然天成的安排,足夠擠進名家之流,讓我敢將自己的設計,加寫進入 Charles H. Moore 的名著,從此與他的技術共存。

在前已刊出的好幾篇文章中,可以見到 INTERPRET 指令的全盤精神,它主宰 FORTH 系統的一切。 FORTH 系統執行起來之後,系統等待著接受輸入。一旦有了輸入,就從系統中比對輸入是否為一個指令? 是,就將其執行掉,不是指令,就試著將輸入轉換成數字,轉得成就放在堆疊上,轉不成就反問使用者,這是甚麼東西?然後永無止境的繼續循環,這麼簡單的主宰工作,就由 INTERPRET 完成。

教科書不教使用者如何用它來設計程式?或如何發揮 INTERPRET 指令的基本精神?我在這裡傳播這種技術,是補技術傳承上的不足,只是聊表善意而已,沒料到好心有好報, 2011 年 4 月起我開始使用 ABC FORTH 系統設計一些略有規模的應用程式,便實踐出了許多 RUN 指令的好處。此前,這些特性,連我這個系統的設計人,自己都不知曉。

系統中的 BASIC 程式,原本只強調用來改善 FORTH 執行數學計算程式的能力,其他的功能,全依靠 FORTH 原有的基本性能,都能另外完成。這樣的思考方式,確實是輕忽了 BASIC 在 FORTH 系統中的地位了,好像只宜將數學計算交給 FORTH 中的 BASIC ,其他的都不適宜。但是,實踐大型程式的設計後,才發現,其實不然!

三年前,我只耗用了大約 6 頁的程式,設計出 ABC FORTH 數學計算系統。最近卻耗用將近 20 頁的規模,設計出一個性能優越的大型應用程式。為了增加使用上的彈性,還刻意盡量將大型應用程式,分割成最小單元的模組化格式。最後,就靠可以不限使用次數的 RUN 指令,來整理出更清楚明確的結果。 RUN 指令的內容,相當於只有 INTERPRET , RUN 存在於 BASIC 中時,就好像是 BASIC 可以叫用執行無數個 FORTH 系統。他的巧然天成特質,絕對能令人嘆為觀止。

以前,我在使用傳統 BASIC 設計大型信號處理程式時,經常苦於系統不允許使用者,可以同時開啟好幾個被順利執行的程式,而必須進行繁雜的人工操作。例如:我建成過一套系統,能夠自動讀進輸入硬體數據信號,系統可以選擇要不要進行信號的過濾處理?或直接進行從時域(Time domain)轉換成頻域(Frequency domain)的快速傅利葉轉換(FFT,Fast Fourier Transform),最後,還有決策程式必須執行。那時,一次只能開啟一個程式被 BASIC 系統執行,用起來痛苦得很。因此,每當見到 FORTH 同好在精研其他的 BASIC 系統時,我首先向他請教的問題,就是這個 BASIC 一次能跑幾個程式?答案是,就算行,數量也是非常有限的。 ABC FORTH 隨您設計,跑幾個都行,直到系統記憶體容量裝不下了為止,這種性能,靠的就是巧然天成的 RUN 指令。

這個 RUN 指令的性能,首先讓『麵條式程式』不見了,就按照電腦高尚專家的踹言踹語,設計符合他們要求的程式,我將 BASIC 大型程式全面模組化,僅只剩下幾個 GOTO 指令,自由使用於單一模組之內,以少於一個螢幕畫面的短程距離內自由跳躍,沒有看不懂的地方、沒有分析不了的流程、沒有不安全的例外、沒有陷入無限循環的可能,這些缺點,全都不會再在程式中發生了。

不再有開檔數量限制之後,許多程式也不用自己重新設計了,就大方的用滑鼠去複製別的程式,供自己使用。嫌別人純用 FORTH 寫成的程式,不容易看懂,日後會有追查上的麻煩,索性就直接黏貼在上或下方,然後邊追蹤、邊改寫成我的 BASIC 格式程式,結果是程式永遠可以看得清楚明白,更加好用了。這樣做,改成的 BASIC 程式,並不會增加記憶體的耗用量,也不會令執行速度變慢。因為,前引的列首編號不會被編譯進系統,而且 BASIC 式的一列程式,除數學式子之外,都只會被編譯成單一個 FORTH 指令而已,程式被執行的速度當然不會變慢。也沒有多耗用記憶體,這種情況,就形同原為橫式書寫的 FORTH 程式,現在改為直式書寫的 BASIC 程式,如此而已。

這兩段敘述,告訴大家,我改善了 FORTH ,同時也改善了 BASIC 。更有甚著,可以建議有心的讀者,仿照同樣方法,將別的程式語言建進 FORTH 系統後,改善它們的性能。有一位小老弟,熟 LISP ,他也留心國際舞台上用 FORTH 設計出來的 LISP ,何不試試我的建議?自己跟著創造出另外一套別有風味的 FORTH 中的 LISP 。也有人用 FORTH 設計出 C ,何不像我一樣?大膽起用巧然天成 RUN 指令的來源 INTERPRET ,建成之後,絕對能帶給您意想不到的效果。如此必能實現由 FORTH 來統管一切程式語言的性能,這些 FORTH 哲理的高度運用,絕對不是我一個人的專利,但也不是應該由我來實現它們的責任。

像我一樣,單只搞 FORTH 的同好,透過這篇網文,您熟讀融會貫通之後,也應該可以大大增高自己的 FORTH 功力。學一個沒人教您的 INTERPRET 指令,可以在 FORTH 系統中再執行 FORTH ,讓程式有多重層次性,這在除錯系統中的斷點式性能規劃上可以用到。也在 FORTH 駐留後再執行一個 FORTH 時,可以用到。其他還有許多例子可以舉出,用法是不勝枚舉,我寫不完。但請大家記住, INTERPRET 是每一個 FORTH 系統都有的指令,卻不是一個標準指令!

坐而言不如起而行,我就用 RUN 指令將 FORTH 翻譯成 BASIC 給您看。在 Win32Forth 系統中繪出柵格線原為 FORTH 格式單一指令 GRID 的程式如下:

 


: GRID
  green line-color
  0 0   moveto 800 0   lineto
  0 100 moveto 800 100 lineto
  0 200 moveto 800 200 lineto
  0 300 moveto 800 300 lineto
  0 400 moveto 800 400 lineto
  0 0   moveto 0   400 lineto
  200 0 moveto 200 400 lineto
  400 0 moveto 400 400 lineto
  600 0 moveto 600 400 lineto
  800 0 moveto 800 400 lineto
;

直接翻譯成 ABC FORTH 中 BASIC 式程式,但仍然還是 GRID 單一指令的新格式如下:

: GRID   BASIC
10 RUN  GREEN line-color
20 RUN    0   0 moveto
30 RUN  800   0 lineto
40 RUN    0 100 moveto
50 RUN  800 100 lineto
60 RUN    0 200 moveto
70 RUN  800 200 lineto
80 RUN    0 300 moveto
90 RUN  800 300 lineto
100 RUN   0 400 moveto
110 RUN 800 400 lineto
120 RUN   0  0 moveto
130 RUN   0 400 lineto
140 RUN 200   0 moveto
150 RUN 200 400 lineto
160 RUN 400   0 moveto
170 RUN 400 400 lineto
180 RUN 600   0 moveto
190 RUN 600 400 lineto
200 RUN 800   0 moveto
210 RUN 800 400 lineto
220 END
;



這還僅只是第一個直截了當,最簡單的範例。設計大型應用程式之後,還有更驚人的發現,總結下來,就是:

1. 凡是 FORTH 系統中可以單獨被執行的指令,都可以用 RUN 指令直接叫來使用,而且同時用幾次都無所謂。
例子無數:如 ABORT 、 PAGE 、 BEEP 、 SPACE 、 CR 、 HEX 、 DECIMAL 。。。。。 等都可以這樣用。

2. 凡是執行前只需提供數字,執行後不在堆疊上留下數字的任何指令,也都可以用 RUN 指令直接叫來使用,但每一列只限使用一次。
例如:上述所舉的程式翻譯例子 21 1 AT-XY 、10 SPACES 、1000 MS 、42 EMIT 。。。。。 等,可用範例也是不計其數。

簡而言之,這兩條規矩就是:一次 RUN 一個指令, RUN 完不留參數。

這裡僅只是隨便舉幾個例子,但請不要小看這樣的應用。

我一直強調,當初設計 ABC FORTH 系統,只是為了想改善 FORTH 不良於數學計算程式的原始性能,才選擇以 BASIC 格式達到目的,但並未設計出許多傳統 BASIC 該有的指令。例如:傳統 BASIC 中有一個將螢幕清空的 CLS 指令,根據上述實踐出來的性能,巧然天成的由 RUN PAGE 直接代換就能辦到。使用者想跳空三列後才印出執行結果時,不須要使用三次 BASIC中 的 PRINT “ “ 指令,可以改用 RUN CR CR CR 來完成。所有螢幕上游標的控制,與繪圖程式所有的操作指令,都可以直接由 RUN 指令叫用。這些發現出來的性能,代表我未為 BASIC 設計螢幕控制指令,卻由 FORTH 系統原來的性能自然融入了, RUN 指令怎麼不是巧然天成?

上述例子舉用了 RUN ABORT ,也是一項有意義的新發現。我在 2009 年十月刊出的一篇『實係數代數方程式的解法』(Solve algebraic equations of real coefficients 已撤文)網文中,為了要與日本教授 Yuji Kida 所設計的 UBASIC 性能比個高下,直接改寫他的程式,並要求一定要直接改寫得成,不幸遇到一個程式中可以隨便從有限循環中跳出來的指令,阻礙直接改寫,日本人將此指令命名為 cancel for ,當時,我不服輸,硬用系統測試出此指令的性能,結果,最後的解決辦法,是以定義出自己的 CANCEL-FOR 指令,其內容為使用四個 DROP 來達到目的。現在,實踐 ABC FORTH 後的經驗與觀念都更清楚了,事實上,只需在程式結束前,執行 RUN ABORT 便可以了。

為了發展大型應用程式,我必須參考許多很有用之 BASIC 、FORTRAN 。。。。。等舊有大型程式,發現裡面有很多這樣的程式設計方式,這個巧然天成的 RUN 指令,協助解決了這種困惑,當初,我並未為系統中的 BASIC ,設計出可以執行 ABORT 的功能,現在它自己跳出來協助我解決問題了,怎麼不是巧然天成?

自行使用 ABC FORTH 系統累積出來的實踐經驗,增強了我自己使用此系統的無比信念。Charles H. Moore 曾經公開質疑搞原子爐應用程式的人,為什麼要把程式寫成幾萬列?我從這個領域出身,雙方我都不予以否定。但是,現在,我卻絕對有信心,敢於明確的指出,如果搞原子爐的人,非得使用萬列以上的程式來求解問題時, ABC FORTH 數學計算系統,絕對能妥善的代勞,完成任務。

舉例而言,一年調整一次的爐心燃料,就得動到幾千幾百根燃料棒,根根都價值斐然,那麼,為了很有效率的營運這些燃料棒,使用萬列以上的爐心燃料營運程式,也就不足為奇了。這種程式,現在交給我來改寫成 ABC FORTH 系統可以直接執行得出來的程式,我也絕對辦得到。而且,日後發展 64 位元的系統普及之日,這種程式就不需要再行改寫,可以確保它 50 年能用。 50 年,是一個比任何原子爐可用壽命,都要來得更長的年限!我估計,只要勇敢承包這項工程,絕對能從中獲得豐厚利益,但卻是善事一樁,只是現已不喜言『利』,我只在乎如何提供 ABC FORTH 系統?能夠供給大家永遠使用。

除了 RUN 指令外,經由實踐,我還發現了其他也是巧然天成的一些性能,這種現象,意味著已經設計好的系統,還有許多隱藏的特殊性能,連我這個系統設計人都還不知曉,令我大為振奮,深覺更應該加強使用 ABC FORTH 系統來設計大型應用程式的機會,就能累積出更多的成果。

即時性交談(Real time interactive)性能,是 FORTH 與 BASIC 程式語言都具有的特性,也是別種程式語言所缺乏的特性。應用程式設計多了,就很喜歡使用這種一般程式語言不便於使用的特點。如此設計出來的程式,被別的程式語言使用者看過之後,想抄都很難抄去使用,因為它們不適合執行與使用者之間的即時性交談,因此更能顯現出 FORTH 程式語言與眾不同之處。

我們若將即時性交談,鎖定在只對鍵盤的輸入反應上(實際上,則可以是系統內的任何輸入訊息),大致而言,這樣的即時性對談,可以分成兩類,一是希望鍵盤未被碰觸過,則系統不作任何反應,碰了就立即反應。二是系統停下來,等鍵盤被碰觸過後,系統根據鍵盤被壓下之鍵來決定程式執行流程的走向。對應到這兩種狀況的 Win32Forth 系統原有指令為: KEY? 及 KEY 。

那麼,我們如何以巧然天成的設計方式,讓這兩種功能在 ABC FORTH 統的 BASIC 環境內實現出來?第一種狀況,我設計了一個簡單卻能讓程式可以隨時因碰觸了鍵盤便立刻中止執行的指令,稱作 TERMINATED ,內容如下:

INTEGER A$

: TERMINATED BASIC
10 LET A$ = KEY?
20 IF A$ = 0 THEN 50
30 PRINT “ Program has been terminated! “
40 RUN ABORT
50 END
;

如果您希望在一個可能停不下來的迴路內,可以因為鍵盤的碰觸而立即終止,就將 RUN TERMINATED 插入到您想要控制的指定位置就得了,但鍵盤都沒碰觸過,程式的執行就不會中止。請注意!設計 ABC FORTH 的 BASIC 部份時, KEY? 指令根本沒有被規劃進 BASIC ,而且還不必經過任何使用前宣告,便能如上例般直接使用,反而是用來暫存狀態的 A$ 需要先行宣告,可是原為只屬於 FORTH 的 KEY? 指令,卻巧然天成的進了上述 BASIC 程式環境,性能好得很。

同理,您若是希望程式執行到指定位置,便希望透過您是否壓下鍵盤的 Y 或 y 鍵,來決定程式是否要回頭重新執行一遍?設計方法,也是巧然天成的,可以直接引用 FORTH 系統中原有的 KEY 指令,予以完成,系統執行到 KEY 指令時,會自動停下來,碰了鍵盤就有後續結果,設計方式就簡單到如下列所示:


 
-----
-----
190 -----
200 LET A$ = KEY
210 IF A$ = 89 OR A$ = 121 THEN -10
220 -----
-----
-----

兩個完整可以直接使用的測試範例,則如下示:

INTEGER A$

: Y? BASIC
10 RUN PAGE
20 RUN 0 20 AT-XY
30 RUN CR
40 PRINT " Do you wish to print yes? (y/n)  "
50 LET A$ = KEY
60 IF ( A$ = 121 ) OR ( A$ = 89 ) THEN 110
70 RUN CR
80 RUN CR
90 PRINT " No "
100 RUN ABORT
110 PRINT " Yes "
120 RUN 1000 MS
130 RUN BEEP
140 END
;

INTEGER COUNTER

: RANDOM-COUNT BASIC
10 PRINT “ Counting and terminate test is starting now ! “
20 LET COUNTER = COUNTER + 1
30 RUN 1000 MS
40 LET A$ = KEY?
50 IF A$ = 0 THEN -20
60 PRINT COUNTER
70 END
;



感覺出『即時性交談』的效果了嗎?體會出『巧然天成』的意義了嗎?這就是 FORTH 與眾不同的本質, ABC FORTH 使用說明並不需要因此而另行改寫。

我們可以利用上述的幾個特別性能,應用於一個完整的範例程式,以展示從不用這些性能,到妥善利用這些性能,所顯示出來的差別。

此處所舉之例為一個單只根據三角形的三邊長度,來計算出三角形面積的公式,此公式稱為海龍(Heron)公式, Heron 是生活在西元 10 年至 70 年間的希臘數學家,此公式是為了紀念他,才被如此命名。

誰都知道三角形的面積等於底乘以高除以 2 ,這個基本計算方法當然比海龍公式還好用。但是,讀者請注意,古時候丈量土地,沒有現在這麼好的輔助工具,那時只能輕鬆的量長度。想輕鬆的確定一個直角,再量三角形的高度,就有困難了,亂量一通就會引發爭議。所以,大約2000年前的海龍公式,在當時丈量大面積土地時,確實是個很好用的公式。三角形可以作為一切多邊形的基本單元,因此,任何多邊形的面積,都可以只靠量長度而計算出來,所以海龍公式很有用。

要設計這個程式並不困難,我們拿它來作為範例的目的,主要是想顯示,隨便設計一下,也能求得答案。但想讓程式萬用,不怕輸入錯誤,就得經過一點執行程序上的安全處理。又進一步想讓萬用程式真能萬用時,這一章所討論的內容,就能拿來實際應用,利用控制鍵盤的輸入鍵來達到目的。

程式內已經有詳細的發展程序說明了,我們只須刊載整個程式,及其簡單的執行後輸出結果。


 

\ Heron’s formula
\ 海龍公式為一根據任意三角形的三個已知邊長,自動計算出面積的公式。
\ 三個邊長為 A、B、C,而 S=(A+B+C)/2 ,面積則表示為 DELTA 。
\ 公式為:DELTA= SQRT( S*(S-A)*(S-B)*(S-C) )

REAL A
REAL B
REAL C
REAL P
REAL Q
REAL S
REAL DELTA
INTEGER A$

\ 最精簡程式

: HERON1 BASIC
10 PRINT " Please input A and B "
20 INPUTR A , B
30 LET { P = ABS ( A - B ) }
40 LET { Q = A + B }
50 PRINT { " C must be > " ; P ; " and < " ; Q }
60 PRINT " Please input C "
70 INPUTR C
80 LET { S = ( A + B + C ) / 2 }
90 LET { DELTA = SQRT ( S * ( S - A ) * ( S - B ) * ( S - C ) ) }
100 PRINT { " delta = " ; DELTA }
110 END
;

\ 增加安全檢查性能

: HERON2 BASIC
10 PRINT " Please input A and B "
20 INPUTR A , B
30 LET { P = ABS ( A - B ) }
40 LET { Q = A + B }
50 PRINT { " C must be > " ; P ; " and <" ; Q }
60 PRINT " Please input C "
70 INPUTR C
80 IF { ( C > P ) AND ( C < Q ) } THEN 110
90 PRINT " It’s out of range, re-enter Please! "
100 GOTO -50
110 LET { S = ( A + B + C ) / 2 }
120 LET { DELTA = SQRT ( S * ( S - A ) * ( S - B ) * ( S - C ) ) }
130 PRINT { " delta = " ; DELTA }
140 END
;

\ 增加即時交談性能

: HERON3 BASIC
10 PRINT " Please input A and B "
20 INPUTR A , B
30 LET { P = ABS ( A - B ) }
40 LET { Q = A + B }
50 PRINT { " C must be > " ; P ; " and < " ; Q }
60 PRINT " Please input C "
70 INPUTR C
80 IF { ( C > P ) AND ( C < Q ) } THEN 110
90 PRINT " It’s out of range, re-enter Please! "
100 GOTO -50
110 LET { S = ( A + B + C ) / 2 }
120 LET { DELTA = SQRT ( S * ( S - A ) * ( S - B ) * ( S - C ) ) }
130 PRINT { " delta = " ; DELTA }
140 PRINT " Repeat? (y/Y) "
150 LET A$ = KEY
160 IF ( A$ = 89 ) OR ( A$ = 121 ) THEN -10
170 END
;

((
\ 執行記錄

FLOAD 'C:\Win32Forth 6.14.00\ISO2011\海龍公式.F'  ok
heron3 
Please input A and B ? 3 4.0
C must be > 1.000000000 and < 7.000000000 
Please input C ? 5.e0
delta = 6.000000000 
Repeat? (y/Y) 
Please input A and B ? 3.00 4e0
C must be > 1.000000000 and < 7.000000000 
Please input C ? 5
delta = 6.000000000 
Repeat? (y/Y)  ok

))



20260802 編後記:

1. 我在所有後來發展的 ABC FORTH 系統中,為了簡化連續使用 RUN 與 連續使用 LET 指令時的方便,從第二列使用 RUN 指令開始,可以只用 => 符號式指令取代,而且不必再用列號。同理,連續使用 LET 指令的情況相同,可以只用 :: 符號式指令取代,也不必再用列號。

2. 我在貼出本文前,刻意修改了 HERON 程式,令其可在 Lina64 Forth 系統中也能執行。修改成果與執行結果列示如下:


 
\ Heron’s formula
\ 海龍公式為一根據任意三角形的三個已知邊長,自動計算出面積的公式。
\ 三個邊長為 A、B、C,而 S=(A+B+C)/2 ,面積則表示為 DELTA 。
\ 公式為:DELTA= SQRT( S*(S-A)*(S-B)*(S-C) )

7 REALS A B C P Q S DELTA
INTEGER A$

: HERON BASIC
10 PRINT " Please input A and B "
20 INPUTR A 
25 inputR B
30 LET { P = ABS ( A - B ) }
40 LET { Q = A + B }
50 PRINT { " C must be > " ; P ; " and < " ; Q }
60 PRINT " Please input C "
70 INPUTR C
80 IF { ( C > P ) AND ( C < Q ) } THEN 110
90 PRINT " It’s out of range, re-enter Please! "
100 GOTO -50
110 LET { S = ( A + B + C ) / 2.0 E 0 }
120 LET { DELTA = SQRT ( S * ( S - A ) * ( S - B ) * ( S - C ) ) }
130 PRINT { " delta = " ; DELTA }
140 PRINT " Repeat? (y/Y) "
150 LET A$ = KEY
160 IF ( A$ = 89 ) OR ( A$ = 121 ) THEN -10
170 END
;

執行結果:

ching@ctt:~$ ./l

AMDX86 ciforth 5.3.0 
fload heron.f
A : ISN'T UNIQUE                                                
B : ISN'T UNIQUE                                                
C : ISN'T UNIQUE                                                
 OK
heron

Please input A and B 
? 3.0 e 0

? 4.0 e 0

C must be > 1.0 E 0  and < 7.0 E 0  
Please input C 
? 5.0 e 0

delta = 6.0 E 0  
Repeat? (y/Y)  OK