2011/10/16

資訊學院的30門課-演算法與google code jam

Google Code Jam 2009我參加過一次,依當時的評分標準,至少要能寫出一題,能夠在限定時間內跑完的code,才能晉級。但是幾乎都是要用dynamic programming的技巧,我用遞迴解一題後,想當然爾,效能不佳,所以我就放棄了。

大家可以上去看看
http://code.google.com/codejam/

既然是軟體,就不能不講到正在全球各地舉行的google code jam 2011,

難度極高,在資格賽的幾個題目中,解出來的難度不高,但是要在極嚴格的執行時間跑出來,

就不能夠亂寫囉,除了要有一台不錯的運算平台之外,挑選的程式語言也很重要,例如很多人用C/C++,

但是最重要的莫過於演算法了。因為這些題目都會讓人無意間進入一種迷思,大部分是divide and conquer的題目,

但是重複計算了一部的運算而不自知。而且某些題型在小範圍的資料中,可以使用遞迴解,但是太多層function call又往往使效能不彰。

演算法教科書提到dynamic programming,當初課本只有兩個範例,所以其實讀的不是很懂,這兩天我又去書局罰站了,翻了一下培養與鍛鍊程式設計的邏輯腦。其實只是用二維或者三維array把之前算過的值儲存起來,碰到一樣的狀況,就直接查表就好,大家都知道查表可以很快,就不用丟到遞迴裡或者loop裡去跑了。不過我相信以mis的programming應用角度而言,不要說dynamic programming,連遞迴我也只用過兩次。

另外瀏覽一下放在他隔壁的Short Coding 寫出簡捷好程式-短碼達人的心得技法
不過這本書是會讓人頭暈的書,很多觀念以前都讀過,
有些小技巧的確在不失可毒性的狀況下,可以讓程式更短,甚至縮短巢狀level,讓程式更好看,有空可以看看啦,但我真的如果如書這樣寫出來,我自己都會頭暈吧。




談到google程式大賽

雖然我不曉得程式怎麼寫效能才高,但可以分享為甚麼我的程式跑的慢,為甚麼大的資料集運算很慢,

一般網頁或視窗是程式設計課程中,都沒有注重在如何讓程式跑的最快,有志參加的coder,一定要記得這些重點才能晉級。

2011我做的是第三題

Problem C. Candy Splitting

http://code.google.com/codejam/contest/dashboard?c=975485#s=p2

提示一下,弟弟的加法就是XOR,哥哥才會進位的加法。這樣題目就容易理解了。

像我這種程式效能上的差異,不是單純使用高級硬體就能cover掉的。

#include
#include
#include
using namespace std;
int main(int argc, char *argv[])
{
int compute(int *candy, int candyNum, int s, int x, int p, int max);
FILE *input;
int i, j, x, sum, ans;
int looptime, candyNum;
int candy[1001];
input = fopen("D:\\Dev-Cpp\\3-test.txt","ro");
fscanf(input,"%d",&looptime);
for(i=0; i
fscanf(input,"%d",&candyNum);
sum = 0;
x = 0;
for(j=0; j
fscanf(input,"%d",&candy[j]);
// sum += candy[j];
}
for(j=0; j
//printf("%d ", candy[j]);
sum += candy[j];
x ^= candy[j];
}
//printf("=%d",sum);
ans = compute(candy, candyNum, sum, x, 0, 0);
printf("Case #%d: ", i+1);
if(ans==0) {
printf("NO\n");
}else{
printf("%d\n", ans);
}
fflush(stdout);
}
system("PAUSE");
return EXIT_SUCCESS;
}
int compute(int *candy, int candyNum, int s, int x, int p, int max) {
int max1,max2;
int a, b;
if( candyNum == 0 ) {
return max;
}
a = x ^ candy[0];
b = p ^ candy[0];
if(a == b) {
max = (max<(s - candy[0]))? (s - candy[0]): max;
}
//printf("[ a=%d, b=%d, x=%d, p=%d, max=%d ]", a, b, x, p, max);
max1 = compute(candy+1, candyNum-1, s-candy[0], a, b, max);
max2 = compute(candy+1, candyNum-1, s, x, p, max);
return (max1>max2)?max1:max2;
}
這邊用到recursive去解,雖然CS教科書上recursive的例子很多,但在google code jam的題目中,
幾乎都是效能殺手。
max1 = compute(candy+1, candyNum-1, s-candy[0], a, b, max);
max2 = compute(candy+1, candyNum-1, s, x, p, max);
因為例如「第三堆到第六堆的XOR」與「第四堆到第七堆的XOR」,其中「第四堆到第六堆的XOR」是不是被重複算了。
資料集越大,被重複算的運算就越多,程式就越慢。
到這邊是不是有大大已經想到,大的資料集要怎麼處理了呢?

Acer Ultrabook挑戰tablet

自從平板電腦出現,因為輕巧、觸控螢幕、待機時間又長,許多民眾就捨棄傳統筆記型電腦,改用平板,使得宏碁、華碩等「筆電」大廠都曾一度低潮,後來華碩推出平板電腦「變形金剛」反攻,佔有16%市場;而今天宏碁發表新款筆電,號稱史上最輕、最薄,宏碁信心滿滿,說要靠這台終極武器,掀起傳統筆電市場的「換機潮」,還要收復被平板電腦的搶走的市場。

主持人:「筆電的散熱設計,讓我們每天大量使用…。」

高窕美女走秀,這場景沒什麼特別,但她手中這台筆電,卻是宏碁想用來絕地大反攻的秘密武器!

自從平板電腦問世,筆電市場急速萎縮,2009年之前,每年都還有20到30%的成長率,隔年銳減到10%,而今年更萎縮到只剩5%,反觀平板,全球一年出貨量就超越5000萬台,過去以生產筆電撐起一片天的宏碁,完全被平板電腦給打趴。

宏碁總經理林顯郎:「Acer現在剛跌倒,跌倒6個月,2011(這台筆電)會啟動一波非常非常大的換機潮。」

新機發表會上直接放話,要靠這台筆電東山再起,這麼大的口氣,信心全來自號稱史上最輕、最薄的筆電規格,13.5吋,厚度只有1.3公分,比直立的1元硬幣還要薄,而重量不到1.4公斤,只比一般平板電腦多500克,卻是功能齊全,有320G的硬碟容量,螢幕也比平板大1倍,而價格更壓在3萬5以下。

超薄筆電不但要單挑平板,宏碁更誇海口,在全球2.9億台筆電市場中,要佔領3成,出貨量可能上看6000萬台。分析師林明謙:「筆電在這一塊的話,事實上是有機會喔,從這個下半年第四季推出後,到明年上半年去扳回一城。」

同樣也是NB大廠,華碩早一步用這台變形金剛守住地盤,在平板市場中,還有約16%的市佔率,接著也要推出超薄筆電換手進攻,現在輪到宏碁先上,是不是有機會收復失土?外界都在拭目以待。


ch6 結論 wireless lan 802.11

第六章、結論

前面各章節說明了無線網路的概念以及無線網路實驗平台的架設方法與過程。欲架設這樣的一個無線網路的實驗平台,除了必須對無線網路卡驅動程式有一定程度的瞭解之外,作業系統的架構也是一個很重要的部份。

對於實驗平台之作業系統的選擇,必須在乎其可取用性、普遍性與實用性,如此一來,研究實驗才可能與實際上的使用結合在一起。Linux作業系統目前正被廣泛的使用在網際網路的機台上。由於其由發展初期至今,經過世界各地無數菁英競相投入,已成為世界公認極為實用、穩定的作業系統。而它的程式碼完全公開,使得使用者可以很容易的對系統加以修改,各是十分具有學術上的研究價值。當然,在這樣環境下建構出來的實驗平台,將使我們可以對整個系統掌握更多的控制權,這對於無線網路上實驗的範圍與方式,也相對的更具彈性。

application的效能測量的觀點來看,由driver層次對整個封包的傳輸與接送的情形進行監控,不僅可比由Application層來觀察更為仔細,也更為詳盡。對於原本不能在Application層控制或觀察的現象,我們也可以在較低階的driver layer中作更進一步的測量與評估。

我們最後由實驗證明,利用這樣的實驗平台可以幫助我們去驗證在無線網路上,許多通訊協定與演算法的實際效能與表現。我們可以藉由這樣的平台去評估修正一通訊協定的部份參數,其性能表現會改變如何;同時,對於其他新的構想的演算法,在這實驗平台上,也提供我們一個實作的好環境。

在未來繼續的研究中,除了可以將更多的實驗用於此實驗平台外,我們還可以在監測控制中繼續作深度和廣度的延伸;除了可以對更多的統計數據作更多的記錄外,也可以嘗試將整個實驗平台的操作介面再更加人性化,讓測試者可以更輕鬆地使用這個實驗平台;同時整個實驗平台在不同作業系統下的移植,也是一個很好的繼續發展目標。

2011/10/15

ch5 實作與測試 wireless lan 802.11

第五章、實作與測試

第一節、multihop

ad hoc的網路架構下,任兩台mobile若在彼此的通訊範圍中,則兩台mobile可直接互相通訊。目前一台使用無線網路卡的mobile的傳輸距離大約有兩百公尺,但限於地理位置以及各種地形的障礙和其他元件的干擾,真正的傳輸距離往往僅僅有幾十公尺。在這樣短距的傳輸範圍中,兩台mobile很可能因為相距太遠而無法直接通訊。此時若是能利用moltilhop的觀念在兩台相對遠距的mobile中,尋找另一個mobile當作轉傳的收發站,則可用接力的方式,來達成兩台mobile的通訊。

第二節、程式實作

在我們所使用的無線網路卡中,因為主要是使用在有基礎架構之無線區域網路(infrastructure Wireless LAN)上,所以其驅動程式僅採singlehop的方式作資料的傳輸,在這樣的情況下,mobile並不會自動轉傳所收到的封包。另外的一個問題是,驅動程式會要求硬體過濾MAC address不屬於自己的封包,所以能到達軟體控制層的封包,不是屬於本機的,就是廣播式的封包,所以那些收送不屬於自己的封包,會在硬體層就被攔截下而停止往上傳送,根本也沒有辦法加以處理。因此,若是要實測multihop的情形,我們必須針對這兩個性質加以改變。我們首先在驅動程式中,找出有關封包收送模式的function,並將期收送模式的旗標改為promise的方式。接著我們嘗試將由硬體送來的封包再轉傳一次,利用驅動程式中傳送與接收資料的函式的功能,並改變資料在buffer中的位置使得我們可以在接收封包後立刻再把封包傳送出去,利用此一方式,我們可以讓修改過的mobile當作轉傳的收發站。

第三節、實際環境測試

我們首先需要三台電腦,兩台作為遠距的傳輸,另一台則是用來作為轉傳的收發站。我們把接收的資料mobile稱為DM。把傳送的資料的mobile稱為SM,而修改過驅動程式的轉傳收發站則稱之HM。實驗步驟如下

l 確定三者可以互相直接通訊(telnet)

l DM放置在一固定點,移動SM,並持續的傳送資料給DM(利用Ping or Telnet),直到兩者距離超過通訊範圍而無法通訊為止。

l 利用同樣的方式找出HMDM的通訊範圍。

l HM放置在DM可通訊範圍的距離。

l SM放置在DM無法通訊的範圍。

l 確定在這樣的位置下HMSM可以互相通訊。

l 測試DMSM可利用HM轉傳來互相通訊嗎?

經過實際在資訊科學系系館三樓的測試,我們將DM放置在多媒體實驗室中,移動SM,發現大約到了三樓的樓梯口時,SMDM就無法互相通訊。HMDM的通訊距離相同。於是我們把HM放置在三樓的樓梯口附近,然後把SM放在系館四樓的樓梯口附近;此時SMDM已無法互相通訊,而DMHM之間,以及HMSM之間,仍可以保持資料的傳輸。接下來開始由SM傳輸資料給DM,並觀察DM所收到的封包記錄。經過幾次實驗的結果,我們發現DM經過HM的轉傳,可以成功的收到SM送來的封包,不過在傳輸速度上,以及封包重送率上,利用轉傳的方式,其效能都有明顯的下降。我們認為這是很正常的現象,因為在無線通訊中,無線傳輸的過程本來就是資料發生錯誤的危險地帶,經過multilhop之後,利用無線傳輸的次數增加了,自然也提高資料錯誤的可能性。所以在mutilhop的通訊中,整個資料傳輸的正確率降低,應該是可預期的現象。

ch3 Linux網路作業平台的架設與安裝 wireless lan 802.11

第三章、Linux網路作業平台的架設與安裝

第一節、Linux的架設。

Linux1991年四月, 由芬蘭人Linus Benedict Torvalds(torvalds@kruuna.helsinki.fi) 所獨立草創,之後, 歷經無數版本演進, 才漸漸變成一個完整的作業系統,這發展過程吸引了全球的玩家以及部份商業組織的參予。就一個簡便的角度來看,我們可以把Linux視為架在80x86相容PC上執行的UNIX系統。而關於Linux作業系統架設的方法,因為很多地方都有詳細的說明,所以請直接參考各大BBSLinux版的精華區。

第二節、Wavelan Wireless LAN Card的安裝:

無線網路的網路卡,目前還不能算是普及,故一般Linux附的Kernel Image (/vmlinuz)並沒有support這種裝置。因此,若要使用Wavelan Wireless LAN Card就要重新Compile Kernel,且要是較新版本的Kernel才行。就Slackware 3.1.0 Kernel Source來說,其算是 2.0.0舊版的。

 到果茶小站 ftp henry.dorm10.nctu.edu.tw,抓新的linux-2.1.36 kernel source

get /linux/slackware/Kernel/v2.1/linux.2.1.36

mv linux2.1.36.tar.gz /usr/src

cd /usr/scr

將舊版的2.0.0 Kernel Source 備份: mv linux linux.2.0.0

ƒ 解開新的kernle source

gzip -d linux2.1.36.tar.gz

tar xvf linux2.1.36.tar tar zxvf linux2.1.36.tar.gz

因為driver I/O Address是寫死的,要改的話要去改 Source,詳細說明請見(/usr/src/linux/drivers/net/README.wavelan

n [ wavelan.p.h 原來程式片斷]

static unsigned shortiobase[]=

{

#if 0

/* Leave out 0x3C0 for now -- seems to clash with some video controllers. Leave out the others too -- we will always use 0x390 and leave 0x300 for the Ethernet device. Jean II : 0x3E0 is really fine as well... */

0x300 0x390 0x3E0 0x3C0

#endif /* 0 */

}

n [ wavelan.p.h 修改後的程式片斷]

static unsigned shortiobase[]=

{

#if 0

/* Leave out 0x3C0 for now -- seems to clash with some video controllers. Leave out the others too -- we will always use 0x390 and leave 0x300 for the Ethernet device. Jean II : 0x3E0 is really fine as well...*/

0x300 0x390 0x3E0 0x3C0

#endif /* 0 */

0x300 0x3E0

}

make config

make all

make bzImage

這裡必須要特別注意,一般我們只需要make all make zImage就可以了不過實際上這樣make出來的kernel太大,所以會造成失敗的,因此一定要make allmake bzImage;請參考 /usr/src/linux/README的說明

mv /vmlinuz /vmlinuz.2.0.0

ˆ cp /usr/scr/linux/arch/i386/bzImage /vmlinuz lilo

reboot後,螢幕出現

eth0WaveLAN at 0x30008:00:6A:2A:BE:47 IRQ 10

nwid 0x82-96 2.00 2422 MHz

這就表示抓到wireless網路卡。

第三節、linux Device Driver

Device Driver 是在核心中專門管理週邊設備用的,一般使用者的程式,必須經過系統呼叫才可透過核心應用週邊驅動程式來達成任務。核心中的設備表大致上可以分為兩種:

 字元設備轉換表 (Character device switch table)又簡稱cdevsw

區塊設備轉換表 (block character device table) 又簡稱bdevsw

cdevsw表示cdevsw 結構的陣列,而bdevswbdevsw結構的陣列,至於核心如何知道使用者對那一個設備有興趣,完全取決於設備檔案的類別,主要設備識別碼和次要設備識別碼。裝置檔的openclose系統呼叫需經過兩轉換表的其中一個,mountumount系統呼叫也需要用區塊裝置的裝置openclose。字元特別檔的readwriteioctl系統呼叫經過cdevsw的相對應程式。

n 關於open裝置的演算法:

Algorithm open

Input pathname

openmode

outputfile descriptor

{

convert pathname to inode,

increment inode reference count,

allocate entry in file table, user file descriptor,

as in open of regular file

get major, minor number from inode

save context ( algorithm setjmp) in case of long jump from driver

if (block device)

{

use major number as index to block device switch table

call driver open procedure for index:

pass minor number, open modes

}

else

{

use major number as index to character device switch table

call driver open procedure for index:

pass minor number, open modes

}

if( open fails in driver)

decrement file table, inode counts

}