Saturday, October 3, 2009

[感想]寫程式到底需不需要懂數學?

[感想]寫程式到底需不需要懂數學?
Category:Java 與程式設計
本篇原是發表在Mr./Ms. Days - 網路, 資訊, 觀察, 生活 - 寫程式到底需不需要懂數學?的迴響,我將它稍稍整理一下後重貼如下: 寫程式超過十年,一直很高興自己是數學系出來的,而不是資工本科系出來的。為什麼?

每當我要寫程式時,我腦中自然就會浮現出能簡化步驟,加快效率的方法和定理;我同時能擁有「將問題化成數學題目和演算法」的能力,以及「將數學演算法寫成程式」的能力。有些人說寫程式不用數學,我倒不這樣認為。只要你的程式中含有「邏輯和演算法」的話,那基本上就已經牽涉到數學了。我認為大家在爭論的,是「到底數學應該要用得深還是不用太深」、「只需要基本用法,還是要儘量多用進階技巧」。

寫程式,多多少少都會用到數學,除非你的程式是只在螢幕上印出 "Hello world!" 之類的簡易程式,沒有「邏輯和演算法」可言。不過只要一碰到演算法,效率好的演算法和效率不好的馬上就可以區分出來。之前很紅的「The art of programming」、「The pearl of programming」、「C 精選名題100題」等等的書,仔細翻開來看,裡面在說的,不就都是數學嗎?問題只在於,你想要用在程式裡的,是哪一種演算法?是快的那一種,還是慢的那一種?或者是適合的那一種?

一個從 1 累加到 n (n>1) 的整數運算式,用 for 迴圈累加起來求解,其實就已經是數學,是一種演算法了,只是顯得毫無效率,直接改用梯形公式就可在 O(1) 解決。跑一個 20^1, 20^2, ..., 20^n (n>1,n為正整數)各除以 p (p為正整數)之後,所餘下的各個餘數為何,你可以用 for 迴圈來把每個 20^k 的項次展開 (pow()) 後再去除以 p 求解,當然得花上你 O(n^2) 的時間,並且還要處理長整數數值溢位的可能,但若直接改用模數運算來跑全部,可在 O(n) 內解決,並且不會有長整數溢位的困擾。平平一樣都可以求出解法,但是在效率上自然有差別。

想用到那一種程度的數學,端看需求而已。一千筆資料的「找出某筆資料修改後重新排序」、「每頁任意n筆的動態有序分頁」、「相互交叉比對求得最符合查詢條件的資料之排行榜」、「分析並建立語詞、語義索引資料庫」…等等,有一千筆時的做法,一千萬筆則有一千萬時的做法。需求不同、時程不同,條件不同,硬體不同,而所用的演算法也不一定相同。在不同的地方,選擇適合的方式下去做。有些雞肋的小地方,也不用執著於用牛刀來殺。

另外,有關於邏輯的部份。數學系在 1+1=2 都得先證明它是正確的以後 (需要用到多個定理),我們才敢去用它來計算,也因此我們才敢說:「是的,九九乘法表是正確無誤的,因為我們可以證明 3*2 => 3+3 的確會等於 6」。每一個運算子,每一次計算,我們都必需要小心地去用邏輯推理。a*b 並不恆等於 b*a (你必須先知道 a, b 元素和其 * 運算子的定義,才能證明),c 也不一定等於 c+0 (同樣,你得先知道 c 元素, 零元素 和 + 運算子的定義)。我們用嚴謹的邏輯去推理,去思考,我們才能真正的說:梯形公式的確比for迴圈累加快、模數運算的演算法的確比各項各自展開後再求來得快。

邏輯論、數論、集合論、圖論、離散數學、演算法、資料結構、網路架構,其實骨子不都是數學嗎?Google 或其他知名大公司的面試考題,不是也有很多題目是和邏輯及演算法相關的?如果寫程式不需要較深、較進階的數學的話,那麼何必要用這些題目做為考題呢?

多學會一種技巧,並不會讓你的刀劍變鈍,反而會讓它更加鋒利和光亮。你的程式裡可以不需要用到複雜的數學,而使用簡易的方法,完全取決於你想要你的程式如何運作。但是要注意,在程式的撰寫從 DOS 的單工、其他作業系統的多工、多執行緒、多核心平行處理,一直演化到後來的網路分散式架構時,或許用更宏觀的角度來對待程式撰寫,可以讓我們的程式更具有競爭力和效率,也可以讓我們程式設計人員本身有更寬廣的心,以及具有更高的專業價值。

至今我仍然很慶幸,當初毅然在資工大二時,轉唸應用數學的決定。

No comments: