2009/04/06

寫程式到底需不需要懂數學?

來源:豬言豬語

數 學對於程式設計師來說到底重不重要?!類似這樣標題的討論,在網路上已經不知道被討論多少次了。前兩天又在老同事小白的blog上看到了他的看法。以前正 方總是喜歡拿演算法與效率來表明數學很重要的立場,反方或是最近普遍的觀點是要依照需求。兩方都沒錯,我也有一點小心得跟大家分享。
先來談談「數學」在大家的心中是長什麼樣子。我大學時念的是輔大應數,會選應數的原因是一、我的分數上不了資工,二、應數又跟純數不一樣,是比較偏電腦應 用的(事實上不是這麼回事),應數的全名是應用數學。三、高中時一位要好且電腦很強的同學也是唸輔大應數,所以我就這樣進了數學系。在一般人眼中是個很硬 的科系,那幾年全校1/2的名單中,數學系就佔了一半。數學系所學的數學,跟一般人所會用到的數學不太一樣。除了幾門工科必備的微積分、線性代數、機率統 計外,剩下的都是高深且抽象的數學理論,像是高等微積分、高等代數、幾何學(不是三角形、正方形那種簡單幾何)、拓撲學等。這幾門課程跟本像天書一樣,非 常的抽象(無法畫在直角座標系上),我能畢業也算是一種奇蹟啊~~我真懷疑我那學唸到博士班的同學們,他們的腦袋是不是跟我長得不一樣。

研究所順利考上的嚮往已久的資工所,成為名符其實的本科系學生,本以為可以不用再玩數學了,但我發現我錯了,是不用再玩那些抽久的高等數學沒錯,但線性代 數、機率統計、離散數學等…用了更多的數學,我想不出來有哪門資工研究所的課沒用到數學的。而且你最後的碩士論文要寫出來,數學更是不能少的。你以為玩網 路不需要數學?大錯特錯,裡面一堆機率統計的東西。電機需要數學嗎?當然需要!最基本的傅利葉轉換就夠搞死你了,所有工科的系所都逃不了數學的魔掌。就算 你到了管理學院,會計系要數學、經濟系要數學、連心理系有些領域也需要數學。雖然所需要的數學不盡相同,但都在數學的領域裡。我開始後悔當年沒把數學唸 好,博士班念到一半唸不下去了,其中一個原因是我數學太爛了。

寫程式需要數學嗎?要看程式的目的?那我們就像討論一個簡單的程式,算出1加到100的總和。

完全以程式結果為導向的人,或是訓練有素的程式女/男工,甚至有時連我都會很直覺的寫出這樣的程式:

int sum = 0;
for (int i=1; i<=100; i++) sum += i;

上面這個程式片段還算很容易讓人一眼就看懂,可是我們明明國中時就學過了這種數列級數的算法了,怎麼還會寫出上面這麼笨的程式呢?

int sum = ((1 + 100) * (100 - 1 + 1)) / 2;

或更精簡的

int sum = (101 * 100) >> 1;

這個例子已經被說爛了,我們來來看另一個例子,計算1加到10000,奇數和偶數的總和。用迴圈的話,一樣很直覺得就寫出來了:

int oddSum = 0;
int evenSum = 0;
for (int i=1; i<=10000; i++)
{
if (i % 2 == 0) evenSum += i;
else oddSum += i;
}

很簡單的程式吧!可是我們稍稍的用我們有12年(國小到高中)的數學背景想一下,你可以寫出更精簡的程式:

int sum = (10001 * 10000) >> 1;
int evenSum = 5001 * 5000;
int oddSum = sum - evenSum;

什麼?看不懂?!sum應該知道怎麼算出來吧?就剛剛第一個例子是1加到100,現在改加到10000而已。evenSum呢?簡單的推理一下,1到 10000之間的偶數總和是2+4+6+...+10000,把它們全部除以2的話會變成1+2+3+...+5000,所以1到10000偶數的總和 不就是1加到5000的兩倍嗎?

1加到5000是:
(5001 * 5000) >> 2 兩倍就不用除那個2了,所以不就是上面那個算式了嗎!

那1到10000奇數的總和不就是全部的總和減掉偶數的總合嗎!稍微動一下腦袋,可以讓你的程式變得很有效率。怕別人看不懂?是不會加個註解在程式碼裡面喔!

相信聰明的你,很容易就可以分析出來這兩個例子的兩種寫法,在效能上迶多大的差異,但這不是我在這裡想要表答數學是如何如何增加效率的。我想要表答的是, 我們明明辛苦了12年,學了一堆的數學,為什麼我們要放棄這樣的基本訓練?我們笑美國人的數學不好,請問你又用了多少的數學來幫助你的生活和你的工作?學 了又不用,那不如從小學開始就分科系好了,不喜歡數學、怕數學的,就選完全用不到數學的科系。

我今天不是要大家在寫程式是時鑽研那種演算法、功式等,去計較那些在現在動不動在2GHZ, 3GHZ,雙核心、四核心之下,所省下的那微小的效率。而是你的態度!你寧願多打一些code,也不願動一下腦筋,如果你的態度是這樣子的話,那也是活得 下去啦,不過你的水平就不過如此而已。

你會反駁說,需要用到演算法、要講求效率時,我再去研究一下就好了,幹嘛說的很嚴重似的。今天我們一時興起,要去爬陽明山,沒問題啊,那種程度的山,只要 雙腳健全走得動的人都能爬。如果換成現在流行的登山步道呢?這需要一點點體力才行。如果你要去爬台灣百岳呢?合歡山的東峰算是最簡單的吧?開車到山腳下, 穿個好一點的鞋子、好一點的衣服、多一點的體力,也還不是太大的問題。那爬玉山呢?雖然現在爬玉山已經很方便了,連行李都可以請人幫你背,但平常沒有一些 訓練,要爬上去不是那麼容易的事。你要站在世界的最高點,去挑戰聖母峰,那全世界沒幾個人辦得到,而且辦到的人事前可是經過了嚴格的訓練。

你想把自己擺在什麼位置?你想要成就到什麼樣的高度?如果你只想在小小的台灣,在二、三流的公司裡,打打專案游擊戰,賺個還算可以的薪水,那的確,你不怎 麼需要數學,連軟體工程的理論也不太需要,最重要的唬弄客戶的技術純熟就可以了。去年去了101的37樓面試後,我才知道我了不起只爬到阿里山而已,要登 上MountainView這座山,我必需十倍努力才行。而這個努力不是我在面試前,看看什麼教戰手冊、寫寫網路上的考古題我就能夠通過的,而是必需把一 些數學的訓練熟到變成很自然的反應才行。簡單的問你就好了啦,上面那個用迴圈寫的1加到10000的那個例子,如果10000改用n的話,那需要多少時 間,用大O(big O)來表示。如果你不能很快的推論出是O(n)的話,那你的履歷連投都不要投,在37樓問的問題比這難多了,而且你沒幾分鐘的時間可以作答。去年那次,是 我第二次後悔當初沒把數學學好。

為什麼Google會這麼重視演算法和效率?應該說世界級的大公司都重視,Yahoo、微軟、YouTube…,因為你寫的程式不是給幾十個人、幾百個人 用而已。而是同一時間有幾百萬,甚至上千萬人使用。一個人慢0.1秒好了,一百萬人就10萬秒,超過一天耶。瀏覽一個網頁,慢個幾秒鐘你都不能忍受了,更 何況是一天。你說能不計較演算法和效率嗎?!

你想過什麼樣的生活是你自己決定的,但你想要當個世界級的軟體工程師的話,把學數學就當作是一種修行吧!不要怕沒地方用,因為你時時刻刻都可以用到它。當你的修行到了某個程度,要挑戰高山,就比別人容易多了。

好好好,不想深入就算了,但你不覺得放棄12年的數學訓練很可惜嗎?至少花點腦筋用一下嘛~~,大家都多少用一點,台灣軟體的水平就會慢慢提升了,你說是嗎?

感覺起來大家還是對於我在上一篇文章中的論點不是那麼的了解,我想要表達的是我並沒有要求堅深、精美的數學演算法, 而是要大家在平常寫程式時,多想一分鐘,把你所約到的數學用上來,不需要多資深的數學背景,只要我們在大學以前所學的12年數學就夠了。目的是什麼呢?為 了有一天需要用到更深一層的數學來解決問題時,做好平日的練習和準備。呃...還是無法體會?我再舉個例子吧。

小明跟小華平常在班上的成績都不錯,但小華不愛小功課,常常到了要交功課的前一天,才向小明借來抄。小明基於朋友的立場,常告戒小華說,老師出功課的目的就 是讓我們平常就把學到的東西熟練,這樣到了考試時才會準備的比較輕鬆。小華腦袋不錯,有點小聰明,但就是愛玩,他覺得浪費時間寫那些功課不如拿去控電動, 功課有交出去就好了,老師也不知道是抄來的,考試?!考前三天再熬夜準備就好了。平常的小考、月考小華還應付的不錯,因為小華頭腦其實不差,所以臨時抱佛 腳的效果還不錯。但終於要到關鍵的基測大考了,小華花了一兩個禮拜來熬夜準備,但考試結果沒有比輕鬆準備的小明來的好。

實力是慢慢累積而來的,也許你很聰明,可以在短時間內硬塞進一些東西在腦子裡,但經驗告訴我們,臨時抱佛腳所讀到的書,在交卷後一秒鐘就全忘光 了。就像農夫為什麼平常要努力的耕田、翻土一樣,要播種時再耕就好了,幹嘛平常就要再那辛苦的挖來挖去呢?大家應到都知道這老掉牙的道理,沒有平常辛勤的 耕耘,怎麼會有豐收的成果。臨時翻土,種得活是運氣好,收成的爛是理所當然。

還是有人在「程式目的」這點上做文章,經過我再次的解釋,不知道大家了解了沒?煎荷包蛋不難吧?同樣是煎蛋,有沒有練習還是差很多的。不知道各位 爸爸們,換尿布的工作是不是你們負責?換尿布也沒什麼難的,但你平常沒熟練,臨時要你參加換尿布比賽,你也是會手忙腳亂的。程式目的不是我的重點,我要寫 的程式也不是專要來解決某個數學問題用的,程式裡本來就到處都有數學的影子。平常多練習一點,有一天需要用到大量的數學時,你就能很輕鬆的應付,而不是眼 睜睜地把機會交到熟練數學的人手上。

文言文?白話文?程式可讀性?信不信就是有人連簡單的迴圈也可以寫得亂七糟,也有寫得很複雜的迴圈,讓人很難了解在幹嘛。程式註解才是程式可讀性 的關鍵,我們不是天天都在一行一行的trace別人的code,事實上我們平常也很少看別人的code,除非你是要改作業、最佳化調整、找別人的Bug之 外。不靠註解,要看懂別人的程式真得很累。就像基測的作文,平平都是白話文,但是有人寫出來的文章就是讓人看不種一樣。

下面這個迴圈在做什麼呢?
int a = 1;
int b = 0;
int c = 0;
for(int i=1, j=-2; a<12346; i+=2, j+=2, a+=2, b+=i, c+=j);


6 則留言:

阿咩 提到...

很確定的是 數學與程式設計
是有相關的關係
但是並不是絕對的關係

尤其在在寫圖形程式
更試用到一堆三角函數

所以說...

要開發高效能的程式或是高難度的
數學可能還是要學醫學

Tommy 提到...

To 阿咩,
的確,當初在學計算機圖學時,為了效率
連劃一條直線,當可以講很多數學
更別說線上遊戲那些複雜的圖形

QQQWU 提到...

完了
我是個私立大學生
但數學真的爛到爆炸,沒及格過
那我該如何補救???
數學可以自學嗎? 從國 高中的數學學起

很焦慮....
也很後悔數學沒學好...

版主 提到...

To Lee,
從自己有興趣的著手吧

Jack 提到...

請問文章最末的迴圈,是不是在做:
計算從1至12346之中奇數與偶數的和?

Unknown 提到...

呵呵~~~只會加減乘除的路過!
以前讀資訊科的~~~其實國中教的數學早就忘光光了!
算式也都忘光了,偶數甚麼的也不會算!
只會買東西大約找多少錢知道,但只要超過百位數我就要用計算計算了!
連心算都很差的我,我朋友居然要拉著我去職訓局去學手機應用程式課程!

天那~~~高職資訊科時就易經見過了程式的可怕,這輩子不想再碰甚麼C語言.計算機概論.電子學
高職怕到出社會還在帕~~~呵呵呵呵!
如今卻被我朋友拉著去學我不擅長的程式課程,真不知要說啥了!

2024年React state management趨勢

輕量化 在過去Redux 是 React 狀態管理的首選函式庫。 Redux 提供了強大的功能和靈活性,但也帶來了一定的學習成本和複雜度。 隨著 React 生態的不斷發展,越來越多的開發者開始追求輕量化的狀態管理函式庫。 Zustand 和 Recoil 等庫以其簡單易用、性...