2026年1月2日 星期五

數字轉換成數值

數字轉換成數值


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


數學計算是電腦的主要功能之一,數學計算程式則處理數值問題。數值在被處理成電腦可以執行運算的格式前,僅只是人們可以認得的數字,例如:口語上的一百二十三,寫成人們可以認得的阿拉伯數字時是123,它只是一個數字,一般電腦系統,通常均只將其識別成『字』而不是可以用來運算的『值』。因此,凡涉及數學計算的程式系統,都必須具備將數字轉換成數值的指令,反之,為了顯示運算結果,也必須具備將數值轉換成數字的指令,電腦才能接受人們設計的數學計算程式,執行程式內指定之數學運算,最後,以數字表示方式顯示結果。

近代FORTH,特別是依循ANSI標準設計出來的系統,常令使用者在設計將數字轉換成數值的程式時感到困擾,問題的起因,就在一個設計轉換程式時,常會用到的關鍵性指令:>NUMBER,其標準規格,似乎是被訂定成強調數學計算功能者所不願見到的格式了。

首先,它不處理帶有負號的輸入數字,數學計算怎麼可能不管負數?這個標準原生指令則確實不管,因此,設計數學計算系統者,只好自行在系統中,增加設計補其功能不足的程式。

另外,傳統非ANSI標準的FORTH系統,在處理數字輸入的方式上,通常就將帶有小數點格式的輸入數字,列入等同於>NUMBER之指令亦應處理的對象之一,這種功能,甚至於被設計成隱性的處理方式,讓系統自動記錄,輸入數字有無小數點?有,則在第幾位位數之處,記錄會被留在一個常被稱為DPL的變數內。

更先進的FORTH系統,則將處理數字輸入方面的整個問題,進行了更具彈性的安排,也就是硬將等同於>NUMBER的基本指令,規劃成執行向量式的指令格式,其執行內容,可隨設計者任意調整。

當初,在議定>NUMBER指令的ANSI規格時,可以想像,必定發生過非常混亂的紛爭,因為,事隔十年之後,還能見到許多公開譴責這個指令標準格式的言論。事實上,想實現包括了上述傳統數字轉換成數值所有功能的指令規格,確實不易訂定,因此,不納入規格,反而更能配合後序的千變萬化程式設計。使用者當然會感到麻煩,負數、小數點都得另行處理,整個FORTH系統運行起來之後,有更多的數字輸入識別處理工作要做,而>NUMBER標準指令,只能提供非常有限的數字轉換成數值之功能。有時,系統乾脆不用,僅在系統之INTERPRET內單獨設計隱性處理程式,然後,只按ANSI規格設計>NUMBER顯性指令供使用者使用。

執行>NUMBER指令前後的堆疊上參數之表示說明為:

( ud1 addr1 n1 – ud2 addr2 n2 )

其中,ud表正的雙整數,恆為正數,不管負值。addr1 n1則表待轉換數字之起始位址與字長量,addr2 n2則表轉換到不能轉換時的位址與剩餘字長量,小數點將被視為不能轉換的對象。

傳統FORTH中,等同於>NUMBER的指令,就被稱為NUMBER,其對應規格為:

( addr – d )

addr表待轉換數字之起始位址,d為轉換出來的數值,可正可負。轉換到不能轉換的標界,是空白字元,因此,可以接受數字內有小數點,指令會將位數存入DPL變數。

雖然,ANSI中的>NUMBER指令規格,不太令人滿意,並不表示使用者絕對無法實現數字轉換成數值的程式,只是表示想達到目的時,較為麻煩而已。單憑此一ANSI標準規格的>NUMBER指令,我們仍然能以高階定義的方式,定義出傳統之NUMBER指令來。

下列這個程式就能達到目的,但執行內容則不管小數點的問題。


    
   
: NUMBER ( addr -- d )
  0 0 ROT DUP 1+ C@ [CHAR] - = >R
  COUNT R@
  IF 1 /STRING		\ 去除負號佔用過1個字元量
  THEN 				\ 否則不必去除1個字元之量
  >NUMBER 			\ ( ud1 addr1 n1 – ud2 addr2 n2 )
  NIP 0= 			\ drop addr2, no matter n2 is = 0 or <> 0 consume n2
  IF	R>			\ keep ud2, check sign?
  	IF DNEGATE THEN 	\ ud2 ==> -d
  ELSE	R> DROP		\ drop positive sign, ud2 ==> +d
  THEN ;

應用於一個精簡的立即式中算符程式,可以檢驗此NUMBER指令的性能。

forth definitions
vocabulary ikq
ikq definitions

: nexti bl word number drop ;
: + nexti + ;
: - nexti - ;
: * nexti * ;
: / nexti / ;
: = . ;
forth definitions

\ usage:
\ ikq
\ 123 + 456 * 3 / 2 =

上述NUMBER指令的獲得來源,係J. L. Bezemer所著之”And so Forth”中第3.28章節起所使用的範例程式,網頁網址為:

http://thebeez.home.xs4all.nl/ForthPrimer/Forth_primer.html

原始程式列示如下:

S" MAX-N" ENVIRONMENT? \ query environment [IF] \ if successful NEGATE 1- CONSTANT (ERROR) \ create constant (ERROR) [THEN] : number ( a -- n ) 0. Rot dup 1+ c@ [char] - = >r count r@ if 1 /string then >number nip 0= if d>s r> if negate then else r> drop 2drop (error) then ; 將其寫成較佳的具有層次結構格式則為: : number ( a -- n ) 0. Rot dup 1+ c@ [char] - = >r count r@ if 1 /string then >number nip 0= if d>s r> if negate then else r> drop 2drop (error) then ;


J. L. Bezemer可能是德國人,他們喜歡自成一格的將number指令設計成轉換出單整數的規格,因此,堆疊上參數表示方式的格式為:( addr – n ),與傳統的( addr – d )不同,他們有堅持使用這種number的理由。一方面係此number指令中不處理帶有小數點的數字,另方面係未來系統將以64位元為主,一個雙整數單元能放置的數字,實際上相當大,約為38位數,系統中已不再需要強調使用雙整數,18位數的單整數已相當夠用了。

我所修改出來的程式,與原程式比較,只是去掉d>s,並將2drop改為drop,便可得到( addr -- d )的規格。至於原程式中使用到的(error)常數,可以不用。我在測試Sod64 Forth與MinForth兩套系統時,均遭遇到系統只提供>NUMBER新ANSI規格指令,但不提供傳統FORTH中之NUMBER式規格指令的困擾,後來,從SwiftForth系統使用說明中,讀到遇此困擾時的處理辦法,建議使用者,將數字轉移到PAD緩衝區去,再當一般文字來慢慢地仔細處理,感到如此使用FORTH的技巧,非常拙劣。J. L. Bezemer在教材書籍中列示範例程式,採用以>NUMBER來設計出傳統NUMBER的技巧比較高明。

將數字轉換成數值程式,最常使用於有對談式要求的場合,程式要能讓系統停下來,等待使用者輸入訊息,系統獲得輸入訊息後才繼續執行,而輸入的訊息可為文字或數字,但對系統而言,都是『字』而非『值』。

發展系統時,很需要精簡的對談式功能,以利單個指令或簡明程式的測試。我在發展數學計算系統時,更有這種需求,尤其是面對新到手的系統,必須進行簡單指令測試時更甚。測試時,又以輸入為數字者居多,因此,經常要為新系統添加這方面的功能性指令,我常將其定名為GetNumber。

以SwiftForth為例,說明資料中建議的設計方法為將輸入數字全送到PAD緩衝區去處理:

: input ( -- n )
PAD 5 BLANK PAD 5 ACCEPT >R
0. PAD R> >NUMBER 2DROP DROP ;

其中兩個相關指令的堆疊參數表示方式規格為:

>NUMBER ( ud1 addr1 n1 – ud2 addr2 n2 )

ACCEPT ( addr n1 – n2 )

SwiftForth系統中仍提供NUMBER指令,但其規格為( addr c – n ) 而非 ( addr – d ),與一般FORTH系統不同。而且,其WORD的指令規格,亦與別的系統不同。一般FORTH系統,執行過WORD指令後,堆疊上會自動得到HERE之值,但SwiftForth之WORD不留HERE之值在堆疊上。

在Win32Forth系統中處理數字輸入的典型設計則為:

: GetNumber ( -- n )
CR QUERY BL WORD NUMBER D>S ; \ DROP會棄除負號,故只能用D>S。
: GetFloat ( -- float )
CR QUERY BL WORD COUNT >FLOAT DROP ;

我曾在Win32Forth中設計一次可以輸入兩個數字的程式,記錄如下:

\ : QUERY TIB 80 ACCEPT #TIB ! 0 >IN ! ;
: Get2Numbers ( -- n n )
CR QUERY
BL WORD NUMBER D>S
BL WORD NUMBER D>S CR ;

F83的設計格式則為:

: GetNumber ( -- n )
CR QUERY
BL WORD COUNT NUBER CR ;

在Sod64 Forth系統中,則有NUMBER?指令可用,其規格為( c-addr – d f ),c-addr表打包規格的字串,首個位元組(Byte)要放字長數量,轉換出雙整數d,並留下旗號f。因此,測試程式為:

: Get2d ( -- d d )
BL WORD NUMBER? DROP
BL WORD NUMBER? DROP ;
: Test ( -- )
Get2d D+ D. ;

類似Sod64 Forth或MinForth的系統,均為只能在文字模式( text mode)下操作的系統,其QUERY藉KEY指令設計而成之後,不能以一般系統之使用方式實現對談式輸入要求,必須改以類似SwiftForth說明中的建議,全搬到PAD緩衝區去後再行處理。

MinForth為純ANSI系統,只能在純文字模式狀況下使用,下例可用:

: GetNumber ( -- n )
query 0.
bl word count over c@ 45 =
if -1 >r 1- swap 1+ swap else 0 >r then \ sign > r
>number 2drop r> if dnegate then d>s ;

MinForth中亦有convert指令,顯然也只能操作出ud,而不管負數。指令若不具有處理帶有小數點數字字串的功能,一旦數字出現小數點時,這種數字便只能被處理到該小數點為止的位置,因此,這個系統的數字輸入格式,只能為純整數。

負號因恆在數字前首,尚易於設計處理帶有負號之輸入數字的程式,若想再添加也能處理帶有小數點之輸入數字的功能,將其納入程式,則程式必定複雜。

啟用MinForth系統時,進行各種數學計算所需單一指令之測試,確實被對談式輸入數字的問題困擾許久。後來,思考到所有FORTH系統自身運轉起來之後,豈不是都能自行接受任何輸入數字嗎?使用者何不借力使力,就用系統已經存在的功能,完成處理輸入數字的應有工作,使用者何須還得另外設計程式?於是測試出叫用系統天王指令INTERPRET來協助完成需求功能的程式,如下:

\ Naughty code for the purpose of interactive input numbers.
: GetNumbers ( -- n/d/f ..... )
POSTPONE [ QUERY INTERPRET POSTPONE ] ;

將這個GetNumbers指令應用在對談式輸入數字的程式中時,輸入就可以混合著輸入整數、雙整數、浮點數,輸入數字的個數及秩序均無限制,都能被系統自動轉換完成後,依序放在堆疊上,以供後續指令使用。

GetNumbers指令的設計原理,運用了FORTH系統能夠運轉起來的根本機制,程式中見不到惱人的NUMBER指令,數字自動轉換的工作,是隱性的潛伏在INTERPRET指令之中了。

從Julian V. Noble所著的A Beginner’s Guide to Forth書中可以見到下列用來描述FORTH系統內所謂之外執譯程式( outer interpreter)執行時的封閉流程,這個流程就是FORTH天王指令INTERPRET功能程式的主要內容,其中,將數字轉換成數值,並將其放置在堆疊上的部份,就是我利用來設計GetNumbers的根據。

The diagram below is a flow chart representing the actions performed
by the Forth outer interpreter during interpretation.


A continuous loop waits for input—from the keyboard, a disk file or
whatever— and acts on it according to its nature. Input consists of a sequence of words and numbers. If a name is recognized it is executed; if it is not in the dictionary (where else would you keep a list of words?) Forth tries to convert it to a number and push it on the stack. If this is impossible, Forth aborts execution, issues an error message and waits for more input.

以上從網上節錄下來的資料,明確的說明了我利用INTERPRET來設計出GetNumbers指令的根本原理,資料出處的網址為:

http://galileo.phys.virginia.edu/classes/551.jvn.fall01/primer.htm

INTERPRET雖不是一個標準指令,但所有的FORTH系統內都有,善加利用,可以設計出許多非凡的指令來。此前,我曾利用它來設計過斷點式的除錯程式,其功能被附加在ABC FORTH系統的PAUSE指令中了。後來,我又發現了利用這個INTERPRET指令便能精簡輕易的從BASIC式程式格式中叫用FORTH指令的特異用法,結果就設計出了ABC FORTH中的RUN指令。這次再度利用INTERPRET設計出GetNumbers指令,算是第三度的精彩運用了INTERPRET。

典型的使用範例如下:


 
\ 整數的質因數分解
: factors ( n -- )
2
begin  2dup dup * >=
while  2dup /mod swap
       if   drop  1+ 1 or             \ next odd number
       else -rot nip  dup . ." * "
       then
repeat
drop . ;

: main ( -- )
cr ." Please enter an integer number: "
cr GetNumbers
cr dup . ." = " Factors
cr ;

執行結果:

main 
Please enter an integer number: 
987654328
987654328 = 2 * 2 * 2 * 123456791 
ok



我在設計ABC FORTH系統的早期階段,便設計出系統在處理實數的環境中,能夠主動將三種數字自動處理成浮點數。純整數、帶小數點數、浮點數三種數字,是使用者可能用到之所有的表示數字,若欲令系統能將三者均自動轉換成浮點數,則必須動手修改天王指令INTERPRET的執行內容,才易於實現要求。幸好,Win32Forth系統中,已將INTERPRET內所需要之相關於處理數字指令(NUMBER),規劃成一個可以改變執行內容的執行向量式指令了,我只須在完成設計後,以轉換向量內容方式,切換指令指向之位址便可。

上述GetNumbers指令雖頗具使用彈性,但得注意其可用規格,它只適合在對談式應用場合,於系統停頓下來後,純粹等待接受使用者只能輸入數字時使用,不適合處理文字,或文字以外另有後續指令的場合。例如:上述以ikq字彙讓系統能執行中算符的應用簡例中,因使用者除了輸入數字外,還可能也要連續輸入指令,這樣的應用,便不適合採用GetNumbers。

相關於將數字轉換成數值的NUMBER指令,在可自動反編譯的FORTH系統中,或較有用的FORTH書籍中,均可找到此一指令的源程式,因ANSI的新規格性能欠佳,使用者便可能常需要自行設計將其改善的新功能程式。因此,所有可獲得之有關NUMBER指令的源程式,便成為可貴的資源,特將屬於書籍方面的資料來源彙整於此,留供日後參考,新資料亦可添加於此。

 

(1). Dr. C. H. Ting, “eForth and Zen”, Offete Enterprises, Inc. 1993, p.64e. NUMBER? ( a – n T, a F ) (2). Dr. C. H. Ting, “Technical reference manual”, Offete Enterprises, Inc. 1989, p.83 (NUMBER?) ( a – d f ) (3). Dr. C. H. Ting, “System guide to Fig-Forth”, Offete Enterprises, Inc. 1981, p.88 NUMBER ( a – d ) (4). Leo Brodie, “Starting FORTH”, FORTH, Inc. 1981, p.279 NUMBER ( a – n/d ) (5). Glen B. Haydon, “All About FORTH”, Haydon Enterprises, 1982, p.65 ( a – d ) (6). Mitch Derick & Linda Baker, “FORTH Encyclopedia”, Forth Interest Group, 1982, p.240 NUMBER ( a – d ) (7). Leo J. Scanlon, “Forth programming”, Howard W. Sams & Co., Inc. 1982, p.180 NUMBER ( a – d ) (8). Martin Tracy, Anita Anderson, Advanced MicroMotion, Inc, “Mastering FORTH”, 1989, Brady books, a division of Simon & Schuster, Inc. p.132 VAL ( a n – d f | 0 ) (9). Mahlon G. Kelly, Nicholas Spies, “FORTH: a text and reference”, Prentice-Hall Englewood Cliffs, N.J. 07632, 1986, p.195 NUMBER ( a – d ) NUMBER ( a – d or n )

沒有留言: