以APL計算黃金比例
APL 語言之中,有一個運算子"power"可以幫助計算數學中的黃金比例。
APL 表達式幾乎與數學定義一樣漂亮、簡潔:
沒錯,只有7個 unicode 字元的表達式,便計算出黃金比例。對數論稍有認識的同仁,也許知道黃金比例的連續分數是:
(圖片連結自維基百科)
其定義不太明顯地使用了遞迴,以一般編程語言表現的話大概離不開:
def phi(N): return 1 + (1 % phi(N)) end
根據數論,無理數只能以無限連續分數表達,即上面圖示中的 "..." 應該無窮盡地延伸下去,才為之正確的黃金比例。而上述函數定義亦導致無限遞迴,定義上雖然沒有錯,但運作上會導致 stack overflow,很難說是正確的程式。
那麼,APL 是如何僅憑十個字元計算出黃金比例呢?或者首先應該問:APL 返回的值正確嗎?以下係Wolfram所給的黃金比例的小數約數:
1.618033988749894848204586834365638117720309179805762862135...
而 APL 給出的值(使用NARS2000實作):
1.618033988749894
可見小數點後16個位被截斷 (truncate) 了,而小數點後1至15位都脗合。先撇除電腦表達、顯示浮點值的複雜問題,1.618033988749894應該是可接受的約數。
下一個問題:APL 表達式是如何達致遞迴?秘訣在於 ⍣ 稱呼作"power"的運算子。
表達式 {1+1÷⍵}⍣≡1 中,⍣ 的作用是
- 呼叫 {1+1÷⍵} 1
- 結果為整數2,與原先的參數(整數1)以函數 ≡ 比較
- 2≡1 返回整數0亦即布林值false
- 如果上一步得出結果為布林值true,則以整數2為答案,否則繼續下一步
- 返回第一步,以整數2作為輸入
也許將 ≡ 函數替換成先把左、右參數列印的匿名函數會比較容易理解:
第一行列印的 ⍺: 2 ⍵: 1就係匿名函數 {⎕←'⍺:',⍺,' ⍵:',⍵⋄⍺≡⍵} 的效果,而下一次呼叫之中,原來的左引數⍺: 2就成為了右引數⍵: 2。
直至最後一次呼叫,⍺與⍵的差異(即⍺-⍵的值)等於(或少於)NARS2000的小數誤差容許度 (comparison tolerance) 3E¯15,⍺≡⍵ 返回布林值 true,遞迴終結並以最後一次呼叫 {1+1÷⍵} 的結果1.618033988749894作為整個表達式的返回值。
解釋到這裏,讀者可能會覺得迷失。事實上我已經思考了良久,都未能得出更好的解釋方法。可以見到APL是一種極度高階及抽象的語言。
最後我再嘗試以一句句子總結 ⍣ 運算子的功能:
設F及G分別為函數,在表達式 F⍣G N 中,⍣ 將 (F N) 的值遞迴地輸入至函數 F,直至 (F N)及 N 以函數 G 比較後得出布林值 true 方告完結。
好像還是有點太抽象。
留言
張貼留言