2012年12月29日 星期六

Haskell: 無盡的路上有foldr真好!

在讀Learn you a haskell for great good時(附帶一提,這本書的插圖好可愛,看的時候會開心^^),和某位苦主(看這裡)一樣有個疑問:為什麼foldr可以處理無限長的串列但是foldl卻不行?

看了好幾次foldlfoldr的定義,都還沒參透的,資質駑鈍的我,只好求助於Google大神。

2012年12月27日 星期四

學習程式語言的感覺?

打從知道可以寫程式和電腦說話之後,只要有空閒,我就會去學習程式語言。我的朋友很少,想說如果學程式語言的話,至少可以有人(?)陪我聊天...

語言是兩個個體之間溝通的工具。無論是人與人之間,或是人與機器之間,若要互相了解,語言是不可或缺的。為了可以看得懂來自外國的訊息,我們會學習英文、日文,甚至是西班牙文、法文等。(附帶一提,我對阿拉伯文有興趣)為了要讓電腦了解我們需要的幫助,我們使用程式語言來描述我們的願望。無論是哪一種情況,語言都是我們讓對方明瞭自己的意志、願望、甚至是感情的工具。

一個語言可以反映出其使用者的文化,讓我們更加了解以這些語言為母語的人們。例如說,學習過日文的人都知道,日文對於兩性之間,以及階級之間的分別相當明顯。以第一人稱詞(我)來說,有男女通用的「わたし(私)」,女性限定的「あたし」,男生較常使用的「ぼく(僕)」,以及男性限定的「おれ(俺)」。程式語言也一樣。Perl,如大家所知道的一樣,是一個具有強大文字處理能力的程式語言。由shell script演化過來的Perl是我所知道唯一一個把正規表達式包含在語言中的程式語言。

為了解土生土長的台灣,以及源遠流長的中華文化,我學習中文;為了解美國的自由、民主、科學與技術,我學習英文;為了解許多稀奇古怪點子的來源,我學習日文。如果還有時間的話,我還希望可以學習阿拉伯文。我想在學阿拉伯文的過程,我可以稍微看見以前那個幅員廣大的阿拉伯帝國以及鄂圖曼帝國,也可以了解以阿拉伯文撰寫的可蘭經真正的內含吧?

程式語言在一開始是設計給電腦看的,就本質上來說應該缺乏感情,或者說,不太容易看到蘊含豐富感情的程式碼。但如果作者傾注他對這份程式的愛,那麼讀這份程式碼的人也必然可以感受的到這股溫暖而強烈的情感。而作者在寫作程式時所遇到的挫折,也會以各種不同的形式讓讀者們看見。(有看過把怨念直接寫在註解裡的人)

所以呢,學習程式語言對我來說不是駕馭電腦的手段,而是一個讓我更能夠了解電腦的一個管道。交朋友的時候,往往會在了解對方更多之後感情更好;對機器也是一樣,在了解機器之後,你就可以理解他的脾氣,也就可以知道機器不合作的理由,甚至是增進你和機器的合作關係。

有人說,學習不同的自然語言(自然演化出的語言)除了上面所說的好處之外,也有助於大腦的健康。所以我希望可以找時間學習阿拉伯文。我很想了解在這個龍飛鳳舞的文字裡面可以讓我窺見的事情。在程式語言方面,對於haskell的許多特點,我很好奇。所以就決定來學haskell啦!

謹向給予我希望的那位可愛的女神祈求,使我可以逐步的完成我的願望。

2012年12月25日 星期二

x86-64組合語言:這個圓多大?

首先祝各位親愛的讀者聖誕節快樂喔!這次的主題是組合語言中小數的操作。感覺起來很無聊?沒錯啦,這主題本身連我聽起來連我都覺得有些無聊。但我還是想要把它貼出來,因為呢,藏在主題下面的東西其實有些小故事可以說。也就是,本文的程式碼是講無趣小故事的藉口。

親愛的讀者,如果之前學習過,或者是欣賞過32位元x86組合語言程式的話(附帶一提,那裡的呼叫協定真的是一團糟),可能就知道在該平台上計算小數的主流是x87 fpu指令。x87 fpu指令可以做純量的數學計算,並且配有80-bit浮點數的計算能力。然而,因為x87暫存器設計的關係,個人覺得該指令使用的難度比較高,用起來比較有被綁手的感覺。

而現在,具有x86-64處理器的cpu具有SSE指令。這套指令裡面就配有小數純量處理的指令,暫存器的使用卻更加的有彈性,用起來也比較開心。於是,在大部份的狀況下,小數的計算利用SSE指令完成,而參數的傳遞,和x64 ABI所說的一樣,也是利用SSE的暫存器(xmm暫存器)來傳遞。

還先不用替x87 fpu掉眼淚。x87指令相對於SSE還是有不可取代的優勢。有些數學函數,像是sin, cos等,如果想要靠硬體來完成,那只能求x87 fpu了。讓x87得以保留飯碗的另一個因素是80-bit浮點數計算能力。總之x87在這幾年應該不會失業,請各位放心 ^_^

剩下的呢,請各位親愛的讀者欣賞一下簡單的程式小品囉。

2012年12月23日 星期日

x86-64組合語言:和C語言一起計算Fibonacci數列!

Fibonacci數列是一個相當知名的數列。它的得名,據說是Fibonacci用來描述用它來描述一對兔子生長情形而來的。關於這個數列許多詳細的資料,以及可怕的公式,可以參閱維基百科OEIS網站、以及這裡

在很多程式語言的書籍裡面,都會把Fibonacci數列的計算放在範例,或者是當作練習題,因為這個數列的計算可以使用到遞迴(Recursion。函數自己呼叫自己。我把這個叫做「把皮球踢給未來的自己」,當然,講得好聽點也可以說是「世代傳承」)的概念。

2012年12月19日 星期三

check: C語言的unit test

在寫程式的時候,我們不斷的重複著修改、測試、修改、測試...的流程。顯而易見的,我們要作不少重複的測試。在理想的情況下,當然是希望親愛的電腦可以替我們代勞:只要我說「請跑測試吧」,電腦就會進行測試,並且告訴我們哪個測試沒有通過。其實,這樣的好事不是天方夜譚,而是一個應該要應用到每個你心愛的程式上面的作業流程!

其中一種測試的方法,把整個程式切割成許多可以測試的小單位,然後依據這些小單位的功能進行一連串的測試。這樣的方式被稱作unit test。

2012年12月17日 星期一

x86-64組合語言:使用程式庫,拓展視野

之前的兩篇(這個這個)組語文裡面是直接使用system call來完成我們的願望。當然,就發現新大陸(?)的角度來看,這是相當有趣的。但如果想要快一點用組合語言來放煙火,那麼直接使用現有的程式庫會比較快。

在組合語言裡面,要呼叫程式庫的功能(用稍微專業點的詞彙來表達的話,是指函數(function)),需要遵守一些既定的規則。就像是親愛的讀者,如果想要搭捷運,就必須在出捷運站以及進捷運站的時候刷卡,不然就算是犯規了。

這套規則主要在描述一個函數被呼叫的時候,必須要怎麼樣安排參數,以及哪些暫存器是可能被更改的,哪些絕對會被保留下來等等的規定。詳細的內容請參考這份文件。

接著來看程式碼吧!想編譯以下的程式碼的話,使用:

gcc put.s

        .section .text

        /*
        這次我們用像C語言一樣的作法來寫
        這次的程式:使用main當作程式的起
        點
        */
        .global main
        .type main, @function
main:
        /*
        x86-64 ABI (user mode)
        參數依照下面的順序傳遞:
        rdi rsi rdx rcx r8 r9

        puts有一個參數:要印出資料的指標
        必須以NULL結尾。
        */
        mov $hello_str, %rdi
        call puts
        
        /*
        rax是函數的return value
        我們希望main傳回0,所以設定
        rax = 0

        xor %rax, %rax
        效果等同於
        mov $0, %rax
        */
        xor %rax, %rax
        ret
        
        .section .rodata
hello_str:
        /*
        .string 後面所接的字串,會由
        組譯器補上'\0' (NULL)
        所以,下面的字串會變成
        "Hello!\0"

        總之,由.string所形成的字串常數
        會變成可以在C語言的世界中方便使用
        的字串喔!
        */
        .string "Hello!"

其實如果很熟x86-64 ABI的人就會發現這個程式碼應該有可以補強的地方。親愛的讀者,看得出來嗎?

2012年12月16日 星期日

x86-64組合語言:利用system call向世界打招呼吧!

上一次的程式裡面使用了簡單的系統呼叫,不過很明顯的,什麼事情都不會做的程式應該沒有任何的魅力吧?那麼,我們何不讓這個程式和我們說幾句話?

就system call的角度來看,要讓程式和外界有所溝通,自然會想到的是read, write等system call。(可以去翻翻asm/unistd_64.h喔~)

        .section .text

        .global _start
        .type _start, @function
_start:
        /*
        syscall : write
        依據asm/unistd_64.h,它的system call number為1
        依據man page (在terminal中輸入man 2 write ),
        它有三個參數:
        參數一(rdi):file descriptor. 1: stdout
        參數二(rsi):裝有想要輸出資料的一塊記憶體空間
                     的指標
        參數三(rdx):上面所說的,那個記憶體空間中的資
                     料大小
        */
        mov $1, %rax
        mov $1, %rdi
        mov $_start_hello_str, %rsi
        mov _start_hello_str_size, %rdx
        syscall
        
        /*
        syscall : exit
        syscall number為60
        */
        mov $60, %rax
        mov $0, %rdi
        syscall
        
        .section .rodata /*read-only data*/
_start_hello_str:
        .string "Hello!\n" 
_start_hello_str_size:
        /*
        _start_hello_str_size這個標籤所在的位置減去
        _start_hello_str,恰好就是Hello字串的長度。
        */
        .quad _start_hello_str_size - _start_hello_str

想要編譯它的話,請使用下面的指令:

gcc -nostartfiles hello.s
我想該寫的都寫在註解上了吧!那麼,請慢用囉~

2012年12月15日 星期六

KDE如果無法啟動軟體的話...?

不想看作文的看官,請點這裡吧!

作文

今天一回家,打開電腦,登入,準備看新聞娛樂更新等等的時候...
「奇怪,按下Alt+F2怎麼沒反應?」(連按)「難不成...」
我試著啟動dolphin,KDE4的預設檔案管理程式。果然...
「沒有啟動...所以應該就是ktimezone了吧?再確定一下好了...」
我點了下左下方的開始功能表,看到它瞬間彈起來的我鬆了口氣,並馬上開始呼叫親愛的konsole同學。對我來說,只要有他,控制整個系統基本上沒問題。
「konsole同學!」
『來了~』
令人安心的黑色視窗呢!
「執行rm ~/.kde/share/config/ktimezonedrc,把ktimezonedrc砍掉吧!」我下了這樣的命令。
『OKOK!』
才說完,那個檔案就從硬碟中被抹除了,「接下來只要登出就好了吧」我這樣想著
回到開始功能表,我打算正常的登出,但很可惜的,登出似乎也受到這個錯誤的影響而無法被啟動... 此時我想到了那個大絕...不到危及時刻絕對不能用的大絕招:Ctrl-Alt-Backspace。
「怎饃辦...算了,賭不會出事吧!」
賭徒魂覺醒的我,便按下了這組致命的快捷鍵。畫面瞬間變得黑暗,並且回到了登入畫面。輸入密碼後,帶著忐忑不安的心情,按下了Alt+F2...
KRunner馬上出現,並且呈現待命狀態。
「終於...」

正經的來了!

來描述一下症狀吧!不知道症狀的話就沒辦法迅速的解決問題了對吧?

  1. 這個問題的症狀是使用KDE桌面的人才會有的
  2. 會發現dolphin以及某些KDE程式會在啟動後一兩分鐘後才彈出可見的視窗
  3. 如果在terminal模式下嘗試啟動這個程式,會看到KTimeZone以及DBus相關的錯誤訊息

簡單的說,這樣的問題有下面的解決方案:

  1. 砍掉~/.kde/share/config/ktimezonedrc
  2. 砍掉所有kde的設定。也就是說,似乎要把~/.kde/下的所有東西都砍掉
    這樣做的話,kde的設定、自訂佈景主題、字型的使用、還有便利貼,都會遺失。在下手前請先備一份

美化你的程式碼,然後貼到部落格上吧!(emacs限定)

很多人都有在blog上面分享程式碼的經驗吧。有些人分享的程式碼沒有經過排版,很難看得懂並利用;有些人的程式碼有排好版,很美觀,也易於再利用(利用<pre>標籤)。但這時候,腦中會浮現一個「想要讓程式碼更漂亮」的念頭:希望程式馬可以有美美的色彩,就像自己的編輯器一樣。我想讀者們也一樣,喜歡看有美美程式碼的部落格吧?

如果你很幸運的,使用emacs當作你的日常編輯程式的話,有個現成的解決方案,叫做htmlize(請Google它,或點這裡)。它可以把你的程式碼,依照emacs的套色方式產生與其對應的html碼。你可以打開所產生的html碼,把相關的部份貼到你的部落格上,或者是像某神人一樣,寫出自訂的emacs lisp來直接輸出適合貼到部落格上的html碼,然後直接貼上。

htmlize有一個好處是,它產生的html碼可以搭配自訂的CSS。藉著使用自訂的CSS,你可以讓貼上的程式碼以你想要的色彩、背景顏色來呈現。

要使用htmlize, 在emacs環境下:
M-x htmlize-buffer
完成後,emacs會把所產生的html碼放到新的buffer中。此時,你可以把程式碼存起來,或者是剪貼相關的部份並且貼到部落格中。所謂相關的部份,是指<script type="text/css">中的所有內容,以及<pre>中的所有內容。

不知道美化的效果如何?各位讀者們可以參考:

  1. 上面所提到某神人的網頁
  2. 我的文章:請點這裡
讓程式碼變得美美的,心情也會變好呢!

2012年12月14日 星期五

x86-64 組合語言中使用 system call

有天,突然臨時起意想要學習組合語言,所以呢首先來熟悉一下一些基本的東西。本程式唯一的功能,是利用sys_exit,一個system call,來結束程式,並把exit code設定為0。(OS:好心酸)。程式碼如下:

.text
        .global _start
        .type _start, @function
        /*
        _start是真正的程式進入點
        在C語言中,編譯器會幫你產生一個可以導向到main的_start函數
        */
_start:
        /*
        注意:
        要把常數輸送到暫存器,使用
        mov $60, %rax
        
        使用下面的指令會把記憶體位置 60 (0x3C)的資料傳送到rax中。
        mov 60, %rax

        sys_exit, syscall number為60  (依據asm/unistd_64.h)
        第一個參數為exit code
        */
        mov $60, %rax /*syscall number傳送到 rax*/
        mov $0, %rdi  /*第一號參數傳送到 rdi*/
        syscall       /*調用sys_exit。程式在此領便當。*/
        /*
        不能用ret來結束。
        _start是「創世函數」,而ret是用來把控制權轉交給呼叫此函數的函數
        所以ret會導致不可預期的結果發生
        C語言的main可以用return(被翻譯成ret),是因為main可以回到_start
        */

想要編譯它的話請使用下面的指令:

gcc -nostartfiles exit.s

這份程式碼使用的x86-64語法是AT&T的語法(AT&T syntax)和Intel官方的語法有很大的不同。其中最重要也是最主要的差異是在運算為的排放。舉例來說,Intel syntax下,把60放到rax暫存器為:
mov rax, 60
但在AT&T syntax下則是:
mov $60, %rax
大部分的x86-64程式設計人員使用的是Intel syntax。但私心覺得AT&T syntax看起來很順眼,而且GNU assembler使用這樣的語法,所以就決定學這一套了。

回到本程式的另一個重點,system call的使用。System call是直接和Linux kernel溝通的方法,可以調用kernel所提供的一些基本功能。依據x86-64 ABI(詳細見這裡),要進行system call,首先要在rax暫存器上面填入system call number,接著,在依照rdi, rsi, rdx, r10, r8, r9的順序把參數填入。在這個程式裡面,因為sys_exit的參數只有一個,所以把它填入rdi中。完成上面的佈置後,利用syscall指令來進行system call。

2012年12月13日 星期四

超級戰艦Battleship觀後感(戰列艦)


本部落格的首PO,就獻給電影觀後感吧!

這部電影,Battleship,中文片名為「超級戰艦」。劇情大綱在Wiki都有,所以就省略吧。總之這是一個博物館拯救人類文明的故事。

沒錯,是博物館。年紀一大把的,標誌著輝煌歷史的一架戰列艦,密蘇里號(USS Missouri),在退役後被當作博物館停放在珍珠港,讓人們可以欣賞它,並且回憶起它對美國的付出,以及它一生所見證的一切。就像一位親切的老兵一樣,等著分享他所經歷過的戰爭故事...

以我的角度,看到的這個電影有三個感動點:
  1. 主角們
    男主角和日本艦長的相處、策略以及地主優勢的使用。
    很可惜的,男主角在最後求婚時說的「我可是拯救了世界耶」讓我對他的好感度瞬間降到0。太中二了啦...
  2. 造型亮麗的伯克級驅逐艦的亮眼表現
    被捲入外星人的隔離空間之後,三架戰艦被擊毀兩艘,僅存的伯克級的雷達也無法作用的情況下,配合了主角們的策略,擊敗了三台外星人的戰艦。只能說不愧是美國海軍最新型的戰艦。
  3. 老兵的精神
    私心認為這是本片的命名源頭:密蘇里是戰列艦,也就是battleship。反過來說,它才是本片真正的主角。
    不只是那些老兵,密蘇里號一定也不想只是待在珍珠港那裡觀戰吧。「什麼都不能做」的感覺很糟呢。還好主角願意賭一把,讓這些外表凋零但內心火焰卻熊熊燃燒著的的老兵們上場。這一睹,拯救了全人類,也讓老兵們有最後一次大展身手的好機會。
    當他們從戰艦的角落走出來的時候,我就知道他們想參戰;當它的引擎被發動的那一刻,我就知道它也想參戰。「看著同伴死去的痛苦,我會加倍奉還。」一定是這樣想著的吧。
    所以才會不合常理的有彈藥的庫存XD
看著密蘇里對抗最後的外星人戰艦,有如看著過去與未來交錯出的美麗畫面。因為我喜歡歷史,而這部電影除了絢麗的煙火外,最棒的就是可以認識這些英姿煥發的船還有它們的經歷。