文章

顯示包含「運算子」標籤的文章

APL運算子

圖片
在前幾篇文章之中的例子都有使用或者提及 APL運算子(operator),用的時候都沒有好好解說。 主流語言中,運算子一般作用在變數或值之上,以導出新的值。 舉例來說,Java 語言之中有數學運算子、邏輯運算子等等。以邏輯運算子為例,表達式 A != B 中使用了 !=  邏輯運算子,假如變數 A 及 B  的值分別為  1  及  2, 那麼表達式即可被演繹為 1 != 2 ,繼而導出新的布林值 true 。 APL 之中,運算子並不作用於變數或值,而是函數之上。所返回的是導來函數 (derived function)。以運算子建立的新函數,使用方法與內建函數無異。 舉一個簡單的實例,用 reduce 運算子 / 配合內建函數  + ,產生新的函數 sum : +/  於之前的帖文中出現過好幾次,相信不難理解。另一個頗為有趣的 commute 運算子  ⍨ ,將函數的左、右參數對調: F⍨ 的作用就好像導來函數  {⍵ F ⍺} 一樣,將自身的左、右參數對調 (即 commute 的本義) 然後輸入至函數 F 。 再介紹另一個極為強大的 APL 運算子: ⍣  (power)。好似下面例子: ⍣ 運算子的左引數為函數 f ,右引數為整數 10 ,則產生呼叫 f  十次的導來函數。有了 ⍣ 運算子,即時不使用程序語言的 while 迴圈也能做到迭代 (iteration) 的效果。以上例子就好比 C 語言中的  int x = 5; for (int k = 0; k < 10; ++k) { x += 1; } (Power 運算子的另一個稍為進階的使用例子,可以看看 前一篇文章 ) 作為運算子的初步簡介,最後介紹極為常用的  ∘.  外積運算子 (outer product)。配合 ×(乘積)函數說明的話,概念上外積就好像小學生的數學乘法表一樣,將 A 、 B 兩列數分別橫、直排列,再以乘法將兩者的元素結合: ...

Project Euler第八題

圖片
又係編程解題,先看題目: 題目出自 Project Euler第八題 ,要求找出以上1000位數字之中,任何連續13個數字的乘積的最大值。 這條題目早於2017年就已經解答過並提交了正確的答案。當時的APL程式: 毋庸置疑是一場災難,非常驚嘆自己可以寫出這樣笨的程式,也許出於當時對陣列編程的陌生吧。加上劣拙的英語註解,整片程式與一塊廢鐵無異。當時的思路大致如下: 將1000位數字以字串C儲存 字串C轉化位1000個元素的陣列D,D的每個元素相當於數字的每個位數 將陣列D轉化為12個76行 x 13列的二維陣列(因為1000可以被13整除76次) 再將二維陣列的每一行中的13個位數相乘 最大的乘積即為答案 時值2020年,再看到同一條題目,我想到的答案卻是: 程式碼可以大量簡化是因為當中使用了" / "運算子。在雙價 (dyadic) 使用下," / "運算子將左面的函數安插在右面陣列的元素之中,即係函式語言中的還原 (reduction): 以上的表達式,執行起來就好似以下的一樣: 由此可見使用" / "運算子可以大幅簡化程式碼之餘,卻不會犧牲可讀性。更強大的功能係,在函數左方加入數字引數,可以達致區間還原 (partitioned reduction) 如下: 第一個表達式之中,函數  +  並沒有用作還原整條陣列,而是對每三個順序元素還原一次,區間大小由左引數3決定,亦是題解  ⌈/13×/⍎¨C 中  13 ...