2008年12月11日

來自 Sir Paul 的音樂 - 不含 DRM!

阿怪曾經對我說:「從哪裡跌倒,就從哪裡站起來。」他指的是唱片工業在網路上大跌一跤,所以他發憤一定要學會寫程式:既然無法打敗網路,就加入網路吧!

唱片工業面對網路的對策一向是 DRM - Digital Rights Management,也就是在音樂 CD 上或數位檔案裡埋入機關,讓買了音樂的人不能任意拷貝、甚至限制能播放該音樂檔的設備或次數。Apple 的 iPod + iTunes + iTunes store 之所以可以得到那些大唱片公司授權在網路上賣音樂,一般相信 Apple 的 DRM 技術是關鍵因素。

DRM 技術不便宜,而且是個道魔不斷比高的遊戲,不是每個唱片出版公司玩得起的。

近年來聽說也有些人想通了,既然玩不起 DRM 或是 DRM 無效,乾脆就閉著眼睛放任拷貝,當作成名或宣傳的管道,只要紅了,就不難從演唱會賺回來。不過已成名的歌手或團體通常不願意這麼做。

要說名氣,在流行音樂界沒幾個人能和 Sir Paul McCartney 相提並論的。他從 Beatles 時代和 John Lennon 就是 Beatles 的兩大支柱,雖然絕大部分的曲子都寫是 John 和 Paul 合寫的,但聰耳人都聽得出來哪首是 John 寫的,哪首是 Paul 寫的。後來他在 1997 年受英國女王封為 Knight,成了 Sir Paul McCartney。

Sir Paul 以 The Fireman 這個兩人團體為名發表的新專輯 Electric Arguments,竟然是完全無 DRM 的音樂!而且銷售手法真的有意思:

  • 可以 $8.99 買無失真 MP3
  • 可以 $12.99 買 CD 送無失真 MP3
  • 厲害的是,還可以 $29.99 元買黑膠唱片送 CD 和無失真 MP3!對!你沒看錯!黑膠吔!
  • 更神奇的是,在 2009/1/31 之前可以 $79.99 購買限量豪華版的唱片,內含以上所有東西和可以自己 remix 的多軌音檔。
  • 想先試聽?可以直接上 The Fireman 官網聽,免費!而且不是選過的少數幾首的片段喔,是全部 13 首完整呈現!
這樣才對嘛!只要是我喜歡的音樂,要我花點錢當然沒問題!最討厭的就是唱片灌水的行為,整張唱片只有一兩首好聽、三四首能聽,也不一定有試聽的機會(站在唱片行一整張試聽完會被瞪白眼吧?),卻要我花整張的錢。Sir Paul 的作法,讓我真的是聽到喜歡了再買,這一格也是邊聽 Electric Arguments 邊刻出來的。

不管你買哪一種,全部都沒有 DRM,愛怎麼拷就怎麼拷,沒有技術上的限制(拷給別人還是有著作權的問題喔,請自重),可以電腦裡放一份,iPod 裡放一份,手機裡放一份,再燒張 MP3 車上放一份、床頭音響放一份,只要是自己聽,通通沒問題!

但反過來說,這也是試水溫,測試聽眾的行為... 可以拷貝,你還會不會花錢買呢?可以 $8.99 買到 MP3,你會不會買 $12.99 的 CD 呢?我認為 Sir Paul 的老歌迷們,尤其是和他一樣已經當阿公阿嬤的,應該會懶得省這幾塊錢自己花力氣拷貝,直接買 CD 放進 CD 唱機比較簡單,何況還有個美美的 CD 封面可以欣賞。黑膠就更不用說了,有幾個人能自己拷一張黑膠啊?一定是老歌迷直接買回來收藏的。

聆聽這張專輯的成本,從 $0 到 $79.99,你要花多少?到頭來這張專輯會賣出幾張呢?製作人賺得回製作專輯和架網站的成本嗎?這對未來唱片工業的行銷方式,有多大的影響呢?

2008年12月4日

Python 3.0 的新玩意(第一部)

真可說是「萬眾囑目」的 Python 3.0 終於在 2008/12/3 釋出了!有興趣了解 Python 3.0 和 Python 2.x 有什麼不同的人可以去讀 GvR 寫的 "What’s New In Python 3.0",這篇是我讀文的筆記。

先記一下,舊的 Python script 可以用 2to3 來轉成 Python 3.0 的 script,可是不見得 100% 轉得完整。

print 從敍述(statement)降級為函式(function)

我的愛好度:heartheart

print "x =", x 這樣的敍述吻別吧!從此要寫 print("x =", x) 了,不過多了一些 keyword arguments 可以修改 print() 的行為,如 sep= 指定字串之間的分隔字,end= 指定印完要加的字(取代預設的換行字元)和 file= 指定要輸出的檔案物件。

我知道 print 沒必要是個敍述,用函式就可以做得很好,又容易自己換掉(__builtins__.print = 新函式就好了),但是為了印個東西打一堆括弧實在很煩,更何況大部分是為了 debug!這時候就想起 iPython 的好處了...

大量用 iterator 取代 list

我的愛好度:heartheartheartheartheart

早就該這麼做了!從此在大多數情形都能用 iterator,在處理大的 list 時就不用擔心會在記憶體多生一個大 list 跑不動了。

xrange()dict.iteritems() 都是極度礙眼的東東,從此完全消失!range()dict.items() 現在傳回的就是 iterator 了。

map()filter() 也傳回 iterator,直接用在迴圈裡又快又省。

比大小

我的愛好度:heartheartheartheart

我常用的 cmp() 和較少用的 __cmp__() 都消失啦!那要對複雜物件組成的清單(list)排序的時候怎麼辦?

看來要愛用 key= 和 operator 模組裡的 itemgetter()attrgetter() 兩個函式了。key= 指定一個函式,在排序時會把清單中的項目一一傳入,函式要傳回用來比較的資料。舉例來說,如果有個 list 是 aList = [ (5,'a'), (3,'z'), (7,'h'), (9,'o') ],要依項目一號排序就這樣寫:
  sorted(aList, key=operator.itemgetter(1))
結果會是
  [(3, 'a'), (1, 'h'), (9, 'o'), (5, 'z')]
如果有個 class Foo 是這樣:
class Foo:
def __init__(self, x, y): self.x, self.y = x, y
def __repr__(self): return "(%s,%s)" % (self.x,self.y)
要把 bList = [Foo(3,'a'), Foo(9,'o'), Foo(5,'o'), Foo(1,'h')] 依 y 屬性排序就這樣寫:
  sorted(bList, key=operator.attrgetter('y')) # 結果 [(3,a), (1,h), (9,o), (5,o)]
要先依 y 排序、再依 x 排序的話:
  sorted(bList, key=operator.attrgetter('y','x')) # 結果 [(3,a), (1,h), (5,o), (9,o)]

整數變大了

我的愛好度:heartheartheart

不用再管 long 和 int 的差別了,不用再見到數字後面那個沒必要的 L 了,因為所有的整數都是無限位數了!(喔,當然記憶體容量是個限制。)好棒啊!

不過 3/5 變成浮點除法 = 0.6,3//5 才是整數除法 = 0。完全記不得以前寫的程式那裡用到整數除法了啊!2to3 不但不會轉除法,連警告都沒有。 Orz

還有八進位整數的表示法也從 0127 變成 0o127(零+英文字母 o + 數字),還好 2to3 抓得到。

字串變簡單了

我的愛好度:heartheartheartheart

以前寫 Python 2.x 的 script 常常在處理中文的時候被文字編碼和解碼搞得昏頭,記不得哪個變數是 unicode、哪個變數是 str,尤其是當資料是從檔案讀進來的時候,然後一個簡單的 c = a + b 都可以因為 a 是 str、b 是 unicode 而吐個很難懂的
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
錯誤訊息。喂!我明明在 script 檔頭指定了 # -*- coding: utf8 -*- 你還搞 ASCII codec?

在 Python 2.x 中直接用引號夾起來的是 str,內容是用 UTF8、Big5、Shift-JIS 等某個編碼系統編好的字串,想建立 unicode 物件的話,要用 str.decode() 來解碼,或是用 u"..." 來夾住文字。
  a = "中文"; b = u"字串"; c = "測試".decode("utf8")
print type(a), a, type(b), b, type(c), c # <type 'str'> 中文 <type 'unicode'> 測試 <type 'unicode'> 測試
這裡 c 是從 string literal decode 得到的 unicode 物件。

到 Python 3.0 的時代,所有 str type 的字串都內建以 unicode 儲存,不再另有 unicode 這個 type,而編碼過的字串或 binary 的資料則用新的 bytes type 儲存。從 str 到 bytes 是 encode,從 bytes 到 str 是 decode。
  a = "中文"; b = u"字串"; c = "測試".encode("utf8")  # b 會有錯誤訊息,因為已經沒必要用 u"..." 語法了
print(type(a), a, type(c), c) # <class 'str'> 中文 <class 'bytes'> b'\xe6\xb8\xac\xe8\xa9\xa6'
這裡 c 是從 str literal 編碼而得的 UTF8 內容,在 Python 3.0 裡是個 binary 的 bytes 物件。

換句話說,不再有字串和 unicode 字串兩種字串了,字串一律用 unicode 表示,非 unicode 的資料則是 bytes,可以用 b"..." 表示。

在 Python 3.0 裡把 str 和 bytes 加起來會得到比較好懂的錯誤訊息:
  TypeError: Can't convert 'bytes' object to str implicitly
開檔也不一樣了。open(filename) 是用 text mode 開啟,所以一定會用某種編碼去解釋讀到的資料,轉成 str 放在記憶體裡(記住,str 是 unicode),預設的編碼會從環境變數 LANG 決定,但可以用 open(filename, encoding="...") 指定編碼系統。如果不想把檔案裡的資料轉成 unicode,或者資料根本不是文字而是 binary data,就可以用 open(filename, "b") 來開檔。用 "b" (binary mode) 開檔讀 bytes data 的確比較容易理解。

非英文檔名也有支援,不過和作業系統有關。

辨識名可以用 UTF8 字元

我的愛好度:heartheartheartheart

變數名、函式名、class 名都可以用中文了!
  彤彤生日 = datetime.date(1997, 7, 5); print(彤彤生日)
這樣子周蟒的功能有一部分就直接被 Python 3.0 實現,更方便了。


(待續)

2008年9月19日

12 歲小朋友設計出「革命性」的太陽能板?

在 slashdot 上看到這則新聞:7th-Grader Designs Three Dimensional Solar Cell。啥?七年級生能設計三維太陽能板?

這篇報導說的,這個設計能吸收可見光和紫外線,吸收光的能力是市售產品的 500 倍!還是最尖端三維太陽能板的 9 倍!剎時之間,好像全球的能源問題因為救世主的出現得救了,這位七年級生還想找業者來製造。

有沒有太誇張啊?

不過在這裡先更正一下許多網友犯的錯誤:不少人把光吸收率(light absorption)誤以為是效率(efficiency),這兩個是太陽能板的不同性質,光吸收率是效率的一環。

太陽能板的效率是指在標準測試條件(STC)下吃掉一瓦太陽來的光能所能輸出的最大電能瓦數。

有關光電轉換的效率問題,我畫了一個「流程圖」方便說明:



要把光能轉換成電能,必須要過五關斬六將:不能被表面反射、不能穿透、要打到光電材料、能量要夠、運氣要好才能打出光電子、歐姆損失要少、還要躲過電洞致命的吸引力,實在有太多機會和途徑會把能量轉成沒用的熱能了,因此通常太陽能板的效率都不好。

補充一下太陽能板效率的標準測試條件。根據 Wikipedia 的說法,測量太陽能板效率的標準測試條件是:

  • 温度 = 25oC
  • Air mass 1.5 光譜
  • 照度 1000 W/m2
一般太陽能板的效率會隨温度上升而下降,隨照度上升而上升,所以有的設計會在板子前面加聚光透鏡。光譜則會很顯著地影響效率,所以必須定義一個包括這三個項目的標準測試條件,才能比較不同太陽能板的效率。

光譜對效率的影響可以這樣理解:低頻的光能量不足以產生光電子,效率為0,太高頻的光產生出來的光電子有太多動能,常會在流動過程中撞到晶格失去能量(失去的能量轉變為熱能),只有光子能量剛好比材料的能溝(energy gap)多一點的會有較高的效率。

因為這個問題,有些太陽能板利用多層材料來捕捉不同頻率的光子:外層的能溝大,抓高頻光子;內層的能溝小,抓穿透外層進來的低頻光子。這樣對整個光譜加起來的效率會比較高。

根據 Wikipedia 的 Solar Cell 一文,目前市面上的效率最好的是 Emcore Photovoltaics 和 Spectrolab 這兩家美國公司的產品,可達 38%。從 Google 搜尋查到實驗室中的最高效率記錄是 University of Delaware 所創的 42.8%

如果十二歲的 William Yuan 的突破是在效率,那 38% * 500 = 19000%,一瓦的太陽能可以產生 190 瓦的電能,能量守恒定律要改寫了!喂喂喂,瑞典的諸公們,看到了沒?現在趕快換今年的物理得獎者還來得及。

言歸正傳,William Yuan 的工作倒底是什麼?

在網路上找不到原始資料。

因為這個原因,Wikipedia 上有關他的條目也有人提議刪除,因為不確定這則新聞到底是真是假。

這個新聞是從美國奧勒岡州 Beaverton 市的地方報 Beaverton Valley Times 的報導開始的,這位就讀該市 Meadow Park Middle School 七年級的十二歲小朋友是今年奧勒岡州唯一得到 Davidson Fellow 獎學金的學生。

對於不住在奧勒岡州的人來說,不是什麼大事。

事情會鬧大到在網際網路上到處傳,當然是因為替代能源的豐富想像力。

在今年八月公佈的 2008 Davidson Fellow 獎學金名單中,William Yuan 獲得美金 $25,000 元獎學金,是三個等級的第二等(五萬、兩萬五、一萬),如果如此「革命性」、「一舉解決人類能源問題」的發明只能得二等獎,那一等獎的一定是光速飛行吧?

Davidson 基金會有個網頁介紹得獎者和得獎原因,我引用其中對 William Yuan 的描述:
In his project, “High Efficient 3-Dimensional Nanotube Solar Cell for Visible and UV Light,” William invented a novel solar panel that enables light absorption from visible to ultraviolet light. He designed carbon nanotubes to overcome the barriers of electron movement, doubling the light-electricity conversion efficiency. William also developed a model for solar towers and a computer program to simulate and optimize the tower parameters. His optimized design provides 500 times more light absorption than commercially-available solar cells and nine times more than the cutting-edge, three-dimensional solar cell.
我看到了幾個關鍵字:3D solar cell、nanotube、light absorption、UV、towers。

怎麼覺得有點熟悉?好像在哪裡看過?

Google 搜尋一下 3D solar cell nanotube...



第三筆和第四筆是這個新聞,但重要的是第一筆和第二筆,講的都是 2007 年 Georgia Tech Research Institute (GTRI) 的研究成果。

有沒有可能 William Yuan 的工作只是重述 GTRI 的研究?

GTRI 去年宣佈的研究成果,發表在 2007 年 3 月的 JOM 期刊
R. E. Camacho et. al., "Carbon Nanotube Arrays for Photovoltaic Applications," JOM 59, No. 3, p. 39.
GTRI 的網站上有論文的全文

我花了點時間讀完這篇論文以後,我對 William Yuan 的工作有了個猜測:

我認為 William Yuan 的工作極可能是利用 GTRI 發明的太陽能板設計,再用一個最佳化程式尋找 Nanotube 幾何形狀的最佳參數。

在談我為什麼如此認定之前,讓我先把 GTRI 的論文介紹一下。你可以先去看看 GTRI 做的介紹動畫,可以讓你對他們做了什麼有簡單的認識。

簡單地說,為了增加太陽能板對光子的吸收,GTRI 的研究人員做出了像城市高樓大厦般的三維結構,讓光子一進入「街道」中就會在「大厦」之間反射,再讓「大厦」都塗有光電材料來吸收光子,就能大幅提升吸收率。比方說,即使吸收率原本只有 50%,來回反射 8 次還不被吸收的機率就降到 0.58,吸收率就變成 99.5% 了。

想法很簡單,但要如何蓋出微觀的高樓?

GTRI 的人用奈米碳管(carbon nanotube)來蓋微觀高樓。

做法是在矽基板鍍了上百萬個微觀金屬片(每片寬度看來不到 0.1 mm),在每一片上長出一條長長細細的奈米碳管,寬度應該是 1 micron 或更小,再在奈米碳管外用分子束磊晶法(Molecular Beam Epitaxy)長出一層碲化鎘(CdTe)和一層硫化鎘(CdS)形成半導體的 P-N junction 當光電材料,最後再用離子輔助沉積法鍍上一層透明的摻錫氧化銦(氧化銦 In2O3 和氧化錫 SnO2 的混合物,簡稱 ITO)來傳導電流並和外界隔離。下面是論文中的示意圖(圖中的 TCO 應是 ITO 的筆誤):



這個研究用上奈米碳管是很有意思的作法,因為奈米碳管不但強度高可以當支架,沿著長軸方向的導電性又好,可以把電洞的電導到金屬片上。此外,因為有多次吸收機會,光電材料可以比一般太陽能板的薄,減少光電子被電洞吃回去(recombination)的機率。

有了這樣的三維結構,光的反射率應該會低很多,我引用論文中的資料圖:



要比較的是 CNT+CdTe 和 Si 這兩條線。在長波長部分這個設計和矽晶太陽能板優劣互見,但很明顯地在 540nm 以下的波長反射率就比矽小得多:只有 0.5%,而論文中說矽的反射率差不多是 50%。你可能注意到,400 nm 以下的已經是紫外線了,換句話說,藉由三維結構的多次反射,連原本很難吸收的紫外線也可以被吸收了,這代表更多可用的太陽能。

不過可惜的是(還好的是)在地球表面的紫外線沒那麼多,記得臭氧層嗎?不然你我早就得皮膚癌了。太陽的光譜如下圖(來自 Wikipedia),地表的是紅色的部分,可以看到短於 400nm 的照度劇烈下降,到大約 300nm 就幾乎是0了。換句話說,雖然三維太陽能板可以吸收紫外線,但這個因素對整體效率的提升助益很有限。



GTRI 做出來的三維太陽能板「單位面積產出的光電流」可達 44.4 mA/cm2,是市售產品的 63 倍,這也是他們的主打文宣。這裡要小心,因為功率是電流和電壓的乘積,光電流有 63 倍不代表輸出功率有 63 倍,也不代表效率高了 63 倍。在效率部分,論文中畫了實測出來的效率和光入射角度的關係圖,不用想也知道從正上方直射下來(圖中的 90o)的時候效率低,有個偏角時候效率高。



效率最高是在 45o 的時候,是 90o 的兩倍(7% / 3.5% = 2)。增加一倍固然很厲害,但這 7% 的效率未免也太爛了吧?論文中自己寫到,CdTe 效率的理論上限是 29%,目前做到最好的只達到 16%,那... 7% 是怎麼回事?

現在講完 GTRI 的研究,再回頭看 William Yuan 的工作...
  • "High Efficient 3-Dimensional Nanotube Solar Cell for Visible and UV Light"、
  • "He designed carbon nanotubes to overcome the barriers of electron movement"、
  • "doubling the light-electricity conversion efficiency"、
  • "developed a model for solar towers"、
  • "a computer program to simulate and optimize the tower parameters"...
除了最後一句有關「電腦模擬和最佳化」的部分,是不是和 GTRI 的研究一模一樣?

在實驗室長出一個用奈米碳管支撐出來的三維太陽能板,我覺得不太可能是 12 歲的小朋友能做的,不是說他無法學會這些東西,但待過固態物理實驗室的碩士班學生大概都知道,從完全不會到長出第一個有功能的樣品,要花多少時間在實驗室裡!更不用說 GTRI 的太陽能板要好幾道手續、用好幾個不同的儀器去長,這些儀器都很貴重,沒有執照恐怕是不能操作的。12 歲的小孩,不太可能拿到執照,也不太可能有足夠的時間耗在實驗室裡煉樣品。

所以我認為他的貢獻是最後一段:寫了個電腦程式去計算在不同的幾何參數下的吸收能力,然後求最佳的幾何。

這樣的程式不用模擬幾百萬個塔,只要用到幾個相鄰的塔就夠了,把塔高、塔寬、塔間距、薄膜厚度、薄膜的吸收係數和波長的關係等參數寫進去,然後把不同波長不同入射角的光當輸入,跑個蒙地卡羅就能得到總吸收能力,再對前幾個幾何參數求最佳化,這差不多是大三到碩士班可以做的題目。

如果 12 歲的小朋友做得出來,的確值得獎勵,差不多是二等獎的程度吧!也許 William Yuan 找到了吸收能力比 GTRI 原始設計高 9 倍的幾何參數呢!但我好奇他是否先用 GTRI 的參數和結果校正過他的程式?

他還在 2008 Intel Northwest Science Expo(就是科展啦!)用 "High Efficiency 3-Dimensional Nanotube Solar Cells for Visible and UV Light" - 幾乎一模一樣的題目得到了物理電磁學組第二名,詳見得獎名單。有趣的是,科展他是和 Vashnav Pandey 這位同學共同參加的,代表這工作是兩個人合作的,怎麼到了 Davidson 獎學金就一人獨飛了?

如果我的猜測沒錯,小朋友的工作真的是電腦模擬,那就算他找到更好的參數,那也只是 7% * 2 = 14%,離解決能源問題還遠得很,更不用說離商業太陽能板的 38% 還差一大截。當然,如果能把效率 42.8% 的分光多材料設計和三維結構結合,也許有新希望也說不定...

2008年9月16日

摻鉻的葡萄酒

今天看到 CodeWeavers 花了十一天把 2008/9/3 公開的 Google Chrome 瀏覽器的開放原始碼專案 Chromium 移植到 Intel Mac 和 Linux 上了。

不用太興奮,這不是 Google 說的 Chrome Mac 版或 Linux 版,而是摻鉻的葡萄酒WINE)。

這個叫做 CrossOver Chromium 的東東,可以從這裡下載得到,但是沒有原始碼!

下載了 52 MiB 的 dmg 檔到手邊的 Intel MacBook,安裝起來約 139 MiB。可以跑,速度還可以接受,Omnibox 的 suggest 功能也正常,移動 Tab 順序時背後應該透明的地方變黑色了,把 Tab 拉出來變成獨立視窗沒問題,可惜拉的時候 Tab 內容就一片空白。這些都是小問題,但無法輸入中文是個大問題,每個字根都變成方塊。



CodeWeavers 自己也說,編出個 CrossOver Chromium 不是要給大家在日常生活中用,而是火力展示,引用 Jeremy White 的話:

In just 11 days, we were able to bring a modern Windows application across to Mac and Linux. Imagine what we can do for you.
換句話說,就像 CodeWeavers 的公司宗旨寫的,這是要證明 CodeWeavers 利用 WINE 把 Window 應用程式移植到 Mac 和 Linux 上的實力;照 Jeremy White 的說法,他們為了移植 chromium 還寫了新的 winhttp DLL 給 https 用。

這個摻鉻的葡萄酒,喝起來有點苦味。

2008年9月15日

Plurk source code 蛛絲馬跡:Python & MySQL

昨天開始玩 Plurk,先不說 Plurk 和 Twitter 或 Jaiku 的差異性在哪裡,網路早就有文章在討論了。有趣的是,今天在噗一個浪的時候,竟然看到了這個畫面:



顯然 Plurk:

  • 是用 Python 寫的 :-)
  • 用了符合 WSGI 架構的 amiweb,原始碼在 Skelotonz 專案裡,但今天下載到的和 Plurk 裡的行數不太一樣,也許 Plurk 用的是稍舊的版本,或是自己改過。
  • 也用了 werkzeug 的 utils.py,本來想放個 link 指到 werkzeug 的 mercurial repository 的,無奈 werkzeug 的伺服器沒裝好,今天放在 mercurial 最新版的原始碼目錄是看得到的,但要看 utils.py 檔案內容就「Internal Server Error」了。
  • 還用了 pastetranslogger.py
  • 最後死在 MySQLdb 要連 MySQL 資料庫的時候,找不到 plurk_group006 這個資料庫。
是有人在「整理」資料庫時「不小心」弄爛了嗎? XD

2008年9月12日

Google Chrome 真的比較快嗎?

Google Chrome 推出已經九天了,網路上的新聞和部落格文章數也數不清,我只想談一件事:Google Chrome 真的比較快嗎?

目前看到的文章大多說二件事:

  1. Google Chrome 啟動極快,一按就發
  2. Google Chrome 的 V8 Javascript 引擎真的快:cnet 的 Stephan Shankland 跑 V8 的五個 benchmarkKai Schmerer 跑 SunSpider benchmark,結果都是 Google Chrome 最快。
啟動是從自己的硬碟把程式讀入記憶體執行,沒有什麼外在變因,應該大部分的使用者都會有一致的感覺:真的比較快。

Javascript benchmark 是從網站下載 Javascript 到記憶體執行,只計執行時間,不計下載時間,所以可以針對 Javascript 引擎的效能做控制變因的比較。

可是使用者關心的速度真的是 Javascript 跑得快不快嗎?

別儍了!

使用者要的是從「打完網址按 ENTER」到「網頁顯示到可以閱讀的程度」之間的速度,也就是 end-to-end 的速度,Javascript 只是眾多影響速度的因素之一,其他如網路的速度、HTML rendering 的速度、載入和執行 plug-in 的速度等等因素,也都會影響。

這一版的 Google Chrome 的 HTML rendering 是 WebKit 525.13,效能和同是用 WebKit 的 Safari 應該接近。

在 9/3 的記者會,Google 決定不展示 Javascript benchmark,而是實地用一隻小 Javascript 程式去下載和顯示 4 個在台灣蠻流行的網站,反覆幾次,計時。這就是 end-to-end 的速度。

有人說過 Never live demo 嗎?

在記者會前我們試了幾次都是 Google Chrome 小幅領先 Firefox 3.0.1、明顯贏過 IE 7。沒想到在記者會當場, 依序跑完 IE 和 Firefox 之後,跑 Google Chrome 竟然小輸給 Firefox! 囧rz

眼睛雪亮的讀者大概都猜得出來為什麼會這樣:網路塞車狀況和被連網站當時的負載都會影響跑出來的結果。此外,這些網站用了大量的 Flash,Google Chrome 每頁的 Flash 都要生新的程序來執行,多了一些作業系統的 overhead,即使 Javascript 狂勝結果總共也只是小贏,運氣差一點碰到網路小塞車就輸了...

可見雖然 V8 大勝 Firefox 3.0 或 IE 7 的 Javascript 引擎,並不保證 end-to-end 永遠會贏啊!


後記:

Firefox 3.1 預定會使用 TraceMonkey,目前的 nightly build 裡已經有了,Brendan Eich 做了 TraceMonkey 和 V8 的速度評比,結果是互有優劣,遞迴的程式 V8 快 10 倍,但在日期相關的部分 V8 慢 4.2 倍,處理 64 進位表示的字串也慢了 4 倍。可以想見,TraceMonkey 和 V8 這兩個 open source 的 Javascript 引擎往後在技術上互別苗頭、互學絕招,還有不少好戲可看,這是刺激的時代!

受益的是誰?當然是你我這些愛上網的使用者囉!

嗯... 在 Redmond 的工程師們一定是在天人交戰吧?該自己寫個更厲害的 Javascript 引擎扳回 IE 8 beta 2 在 SunSpider 大輸 Google Chrome 3.8 倍的顏面?還是該把 V8 或是 TraceMonkey 放進 IE?

啊!我知道了,一定是用出各種手段^H^H力量^H^H方法和管道來宣傳 Silverlight,讓全球的網頁開發者唾棄 Javascript!

2008年9月10日

Large Hadron Collider 要開光了,會有黑洞吃掉地球嗎?

昨天晚上在電視新聞上看到 CERNLarge Hadron Collider (LHC) 加速器將於中歐時間 2008 年 9 月 10 日開始有質子束運行,也就是「開光」啦!(其他網路新聞:slashdotScientific AmercianBBC,啊 ~ Google news search 比較快啦!)

真想不到台灣的電視新聞這麼重視實驗粒子物理!

然後電視就播出下面這段 YouTube video,模擬微觀黑洞從 LHC 生成,再逐漸吃掉附近的物質,最後把整個地球吃掉的畫面。哦,原來今天是世界末日,難怪要上新聞。




CERN 是 Tim Berners-Lee 當初發明 World Wide Web 的地方,可說是沒有 CERN 就沒有 Yahoo!.Google.MySpace.Facebook.Wikipedia.奇摩.無名,等等讓人類找到資訊.找到同好.找到老友的好東西,難道 CERN 也是毀滅全人類的殺手?

在我說為什麼不可能之前,先留幾張歷史性的畫面。


LHC 處女航之 CERN 首頁




LHC 「保證安全」(關心 LHC 內部是否安全的人不多吧?大家最關心的還是地球!)



LHC 的降温狀態,整個 27 公里的加速器全部都在 4.5oK 以下了。




哦,除了黑洞之外,LHC 在 Dan BrownAngels and Demons 書中還是製造出反物質炸彈的地方,大家對尖端科技的想像力還真是令人欽佩。

言歸正傳,到底地球會不會在今天-2008 年 9 月 10 日-因為 LHC 的微觀黑洞而滅亡呢?

答案是:絕對不會!

我怎麼能這麼肯定?我對宇宙有這麼透徹的認識嗎?

當然是沒有,不然我早該拿諾貝爾獎了? *笑*

今天 LHC 不會有微觀黑洞啦!因為今天開光後,只有孤伶伶的幾顆質子聚成一團(a bunch)沿著同一方向在 LHC 的隧道裡繞圈圈,沒有反方向跑的質子,不會碰撞,當然就沒有反應,更不會有微觀黑洞這種反應產物。 XD

LHC 加速器的啟動是分好幾個階段的:

  • 玩玩單方向的幾顆 0.45 TeV 的質子
  • 玩雙向的(像不像 juggling 啊?只是兩個沙袋跑反方向)
  • 試撞
  • 再來就逐漸要上軌道了:更大(每團質子要加到三四百億顆)、更多(156 團)、更高(能量提升到 7 TeV)、更準(聚焦)
  • 玩真的碰撞囉!
真的碰撞要到明年了,所以今天還可以輕輕鬆鬆喝咖啡過日子,不用擔心地球會不見。(其實地球真的不見也沒什麼好擔心了。)

那是不是要趕快造架太空船移民到火星去?

根據 UC Santa Barbara 的 Steven B. Giddings 和 CERN 的 Michelangelo M. Mangano這篇 96 頁的論文,是不必急著移民火星的。

結論簡單說,如果在 LHC 的運轉期間會發生黑洞吞掉地球的事情,那地球早就被宇宙射線和大氣碰撞所產生的黑洞吃掉了,你也不會在這裡看我的部落格。

你強烈要求要有數據證明?

我佩服你的求知慾,來!我端些數字出來。
  • LHC 碰撞頻率 = 每次兩團質子交叉平均約 30 個碰撞 / 每 25 ns 一次交叉 = 1.2 GHz。
  • LHC 碰撞次數 = LHC 碰撞頻率 * LHC 運轉時間 = 1.2 GHz * 20 年(應該不到 20 年,高估一下)= 7.6 * 1017
  • LHC 碰撞能量 = 7 TeV + 7 TeV = 14 TeV。
  • 14 TeV 的碰撞能量相當於 109 PeV 的宇宙射線質子撞到大氣中的質子的能量(請用相對論計算質心能量就知道了)。
  • 109 PeV 的宇宙射線的通量大約是 10-19 m-2 sr-1 sec-1 GeV-1,把能量大於 109 GeV 的、從所有角度來的宇宙射線加起來(就是積分),懶得算了,估數量級吧,大約是 100 km-1 year-1(每年每平方公里被 100 個能量大於 109 GeV 的宇宙射線打到)。這是這樣算的:因為 1 km-1 year-1 是好幾千 PeV 以上的宇宙射線的總合,能量每降 10 倍總通量就上升 30 倍左右,扳一扳手指,差不多就是 O(102) km-1 year-1下圖是宇宙射線在地球量到的通量與能量的關係圖。

    cosmic ray flux


  • 地球壽命大約是 45 億年,地球截面積約 1.28 * 108 km2
  • 地球誕生到現在,這種碰撞已經發生了大約 100 * 4.5 * 109 * 1.28 * 108 = 5.8 * 1019。如果 LHC 在 20 年內會毀掉地球,那地球已經毀滅了 76 次。
既然你還在讀這篇部落格,表示地球連一次毀滅都沒有,所以微觀黑洞就算在 LHC 生成也應該是無害的。

你不服氣?說宇宙射線裡產生的黑洞跑得很快,咻一下就過去了,來不及吃掉地球,LHC 產生的跑得很慢,會留在日內瓦一口一口把地球吃掉。

相對論學得不錯喔!速度的部分說得很對,這就是那 96 頁論文花了很大的力氣在講的,微觀黑洞和週遭物質的交互作用、吸聚過程、和霍金蒸發的問題。這部分牽涉到黑洞理論(廣義相對論)和微觀粒子的理論(場論),學問太大,我也不怎麼會。不過有個簡單的論述總結:同樣的宇宙射線不止會打到地球,也不斷地在撞擊太陽、恒星、白矮星、中子星... 等等天體,如果 LHC 會產生能吃掉年輕又小隻的地球的黑洞,那老扣扣又極高密度的中子星,早就把高能量的微觀黑洞擋下來,被吃得一乾二淨了。現在還看得到不少這種中子星,就是有力的反證。

也許我有偏見,但予其憂心度日、甚至寄死亡威脅信給 LHC 的物理學家們,還是悠閒地喝喝咖啡好了。

Google 也為 LHC 處女航做了好棒的 Doodle 耶!貼個 screenshot。

2008年8月2日

COSCUP 2008 開始報名囉!

萬眾囑目的 COSCUP 2008 開始接受報名了!

今年在 Knight、Bob、及多位籌備人的奔走之下,拉到破記錄的贊助!結餘款會用來支持本土社群的活動

為了讓贊助單位錢花得過癮,以後還想再花,社群朋友在現場請花點時間(如吃茶喝點心的時候)找贊助單位的人聊聊、把贊助單位的傳單搶光,如果剛好在騎驢找馬,就留個聯絡資料給你有興趣的公司吧!一定比三位數或四位數的網站有效的!

2008年7月27日

一蹶不振

啊,不是我跌跤了從此爬不起來,好友們不要擔心...

彤彤寫他的暑假作業,有一部分是含有破音字的成語,我希望他一個一個查,不要唸錯了。查到的第一個就是「一蹶不振」。這個成語我從小都是唸

|ˋ ㄐㄩㄝˊ ㄅㄨˊ ㄓㄣˋ
但教育部可不這麼想!【教育部成語典--修訂本成語】給的注音
| ㄐㄩㄝˊ ㄅㄨˋ ㄓㄣˋ
哇哇哇!原來我的國語爛成這樣!四個字的成語可以唸錯兩個字,慚愧!

「一」和「不」倒底該怎麼唸?顯然要看後面跟的字是幾聲:
  • 一張紙、一船人、一把蔥、一塊玉、一個人
  • 不乖唷、不行吧、不好囉、不要啦
你會怎麼唸?

看看教育部的國語小字典怎麼寫:
  • 「一」:| (「一」字單用或在一詞一句的末尾,念陰平聲;在去聲字前,念陽平聲;在陰平、陽平、上聲之前,念去聲。)
  • 「不」:ㄅㄨˋ (「不」字在去聲字之前,變讀為陽平。)
喂喂喂!教育部,你要教小朋友,可不可以說白話?陰平、陽平、上聲、去聲是什麼,小朋友學過嗎?幹麼不寫一聲、二聲、三聲、四聲?彤彤五年級才第一次在上課時聽到這些東西,老師還說不懂沒關係,以後還會教,這樣子你小字典首頁
本典適用於國小學童及教師,若為其他需求,請詳閱說明。
是開玩笑的嗎?我找了半天,才在建中的網站找到這篇明快解釋陰平、陽平、上聲、去聲的網頁,一到五年級的小朋友如何能懂?

我來當義工家長,翻譯一下好了:
  • 「一」字單用或在一詞一句的末尾,念一聲;在四聲字前,念二聲;在一聲、二聲、三聲之前,念四聲。
  • 「不」字在四聲字之前,變讀為二聲。
那「一蹶不振」依這個規則該怎麼唸?「蹶」是二聲,所以「一」要讀四聲,「振」是四聲,所以「不」要讀二聲,那... 不就是... 我從小就會的唸法?

教育部成語典的注音是錯的!

原來帶給我們「三隻小豬」的教育部成語典竟是如此一蹶不振!

2008年5月4日

當 C++ 的不變性遇上懶人法

聊聊我最近碰到的一個問題:想用懶人法(lazy initialization)提升 C++ 程式的效率,郤碰上不變性(constness)的阻礙,和解決的方法。

寫 C++ class 的時候,常常會寫一些 getter 和 setter 來讀寫物件的屬性,比方說 Person 這個物件有年齡(age)屬性,就可以寫個 getAge() 和 setAge() 來讀取和改變它的值。典型的寫法大約是這樣:

class Person {
Person(int persion_id, PersonDatabase & pdb); // 從資料庫裡抓個人資料進來
...
int getAge(void) const { return age_; } // 傳回 age 資料
void setAge(int age) { age_ = age; } // 改變 age 資料
...
};

Person::Person(int person_id, PersonDatabase & pdb)
{
// 把所有屬性從資料庫讀回來填好
}
這是常見的設計:在 constructor 把所有的屬性填好,並提供 getter 和 setter 函式供其他物件讀寫。

在 getAge() 的宣告加上了 const 表示這個 member function 不會改變 Person 物件的屬性。一開始就把不變性說清楚是比較好的設計,這樣子任何程式都可以呼叫 alice.getAge() 來讀出 alice 的年齡,不論 alice 這個 Person 物件是不是 const 的。

想像政府某單位有個程式要把全國納稅人資料載入,然後對年齡、繳稅金額、教育程度的數據做統計分析。依以上 Person class 的設計,那大概是這樣:
vector<Person> people;
PersonDatabase pdb;
while (pdb.next()) {
people.push_back(Person(pdb.getId(), pdb));
}
這樣做程式很簡單,但有兩個問題:
  • 這樣會在記憶體中建立一千多萬個 Person 物件,每個物件如果需要 100 bytes,那就至少需要 1GB 的記憶體。用現代的個人電腦來看不算多,但如果要處理的國家不是台灣而是日本或美國,那就大多了。

  • 另一個問題是把 100 個 bytes 讀進來,依身分證號碼、年齡、姓、名、地址、繳稅金額、教育程度等等屬性分門別類存在每個 Person 物件的肚子裡,也需要時間。既然我們只要用年齡、繳稅金額、教育程度三項數據做統計,花那美國時間去多讀一堆用不到的屬性、還浪費那美國空間去把這些屬性分門別類存好... 好像蠻白痴的。

現代的資料庫很會做最佳化,用一個 SQL query 就可以把所有需要的屬性抓回來,但 C++ 這邊還是要把抓回來的字串拆開、轉型、再儲存,屬性越多,花的時間仍然越多。

所以這個最簡單的設計不 scalable,在物件內含資料較多或有巨量的同種物件要載入記憶體時會浪費記憶體,也變得很慢。

為了空間和時間的效率,一個普遍的技巧是懶人法: lazy initialization,也有人說 on-demand initialization,做法就是在建立 Person 物件時懶惰一下,不去把所有資料讀進來,等 getter 被呼叫的時候,如果沒有資料,再去讀進來存著和回傳,下次同一個 getter 再被呼叫時就可以直接回傳。這個做法需要多一點程式碼,每個 getter 也會要多花一丁點時間檢查有沒有資料,但可能省下不少空間和總時間。(但如果讀資料庫很慢很慢,可能就不適合這樣做。)

程式大概寫成這樣:
Person::Person(int person_id, PersonDatabase & pdb)
{
// 把所有要從資料庫讀的屬性設成「不詳」
age_ = -100;
...
// 記住資料庫在哪裡,以後可以用
pdb_ = pdb;
}

Person::loadInt_(char * name)
{
// 從 pdb_ 載入指定的屬性,轉成 int 後回傳
}

int Person::getAge(void) const
{
if (age_ < 0) age_ = this->loadInt_("age"); // loadInt_() 會去讀 PersonDatabase 回傳 int
return age_;
}
這樣太棒了!一個設計可以省時間又能省空間。一切都很美好...

碰!
person.cc: In member function `int Person::getAge() const':
person.cc:77: error: passing `const Person' as `this' argument of `int
Person::loadInt_()' discards qualifiers
make: *** [person.o] Error 1
Compile 失敗了!為什麼?

因為在 getAge() 裡呼叫 loadInt_() 破壞了不變性。

getAge() 明明昭告天下是不會修改 Person 物件的,但為了用懶人法,又不得不在沒值時叫 loadInt_() 來把年齡抓回來交差,換句話說,getAge() 會修改 Person 的 age_ 屬性。

Compiler 不准你做這種事。怎麼辦?

這時在觀念上要把介面實作分開。宣告是介面,實作要在符合宣告的精神下達成任務。

getAge() 的宣告可以解釋成:
致所有呼叫 getAge() 的程式:我謹以至誠,不會改變 Person 物件的內容,alice 是 19 歲,我就會回傳 19,而且不會改動任何 alice 的屬性。
照這個宣告的精神,雖然 getAge() 要把年齡屬性載進來,把 alice 的年齡從不詳變成 19 才回傳,但這個行為沒有違反上面的宣告,回傳「不詳」才是違反 getAge() 自己的諾言。

所以程式要這樣寫:
int Person::getAge(void) const
{
if (age_ < 0) age_ = const_cast<Person *>(this)->loadInt_("age"); // 把 this 指標轉成 non-const
return age_;
}
先用 const_cast 把 Person 物件 this 從 const Person * 轉成非 const 的 Person *,就可以呼叫 loadInt_() 了。

要違反自己在語法上的宣告,才能符合宣告的精神,這真是 C++ 的黑暗面啊~~~

2008/6/11 後記:謝謝 fr3@k 的指教,在這種情形用 mutable 關鍵字宣告 age_ 就可以在 const 的 member function 中改動 age_ 了。

網路上有不少文章講 mutable vs. const_cast,我看了幾篇,都是一面倒不建議使用 const_cast,其中一個論點和 compiler 最佳化有關。最佳化是個很大的議題,我不太懂,但如果 const_cast 的使用造成 compiler 不知道這個 const member function 會改到 age_ 而把它最佳化成直接回傳某個 register 中的值,問題就大了。(喂!寫程式寫到要顧慮 compiler 的 bug,會不會太辛苦了點?)

不過我實在不喜歡在 header 檔中宣告 mutable int age_,因為 age_ 是不是 mutable 是實作的細節,不是介面,如果換一個實作也許就不需要用 mutable,實在不想在 header 檔裡寫 mutable。看來要用 pImpl pattern 了... 但是用 pImpl 還是躲不掉 mutable... Orz
class Person {
...
struct Impl;
mutable Impl * pImpl_;
};

2008年4月25日

pyebot 誕生

我幾天前讓 pobot 復活了,在 #tossug irc 頻道上才露臉沒多久就被乃特大嫌了..


<11:25> knight: PingYeh: 叫你家 pobot 改一下名吧
<11:25> knight: PingYeh: 不然這邊 po* 好多個人
<11:25> knight: irssi 打完 po 還要 tab 好幾下才確定有沒有丟錯人 XD
<11:26> PingYeh: knight: pybot?
<11:27> knight: 隨便囉
<11:27> knight: 反正 po* 就有 pofeng PowerOp pobot 三隻, 怕丟錯人 XD
從善如流,今天就改名。

在 freenode 上試了幾個名字:pybot、piebot、ibot、ebot、dbot、qbot 都被註冊走了,bot 還真是多啊!

最後決定叫 pyebot,一方面它是用 python 寫的,一方面我喜歡 π 這個數,保持個唸起來是 π 的名字,還多個 e 在裡面,有兩個超越數了耶!

另外也聽乃特大的建議,幫 pyebot 建了個 blog,以後有關 pyebot 的對話或設計就會寫在那邊了。

2008年4月22日

pobot 復活

From ping不見路

pobot 是支我很久以前用 python 寫好玩的 irc bot,一直掛在 #tossug 的頻道上。但自從 pingyeh.net 2007 年在台大的據點消失之後,pobot 頓失依靠、流離失所,那知搬回家中的 linux 又水土不服,就此一病不起...

在阿怪的力促之下,上個週末花了點時間,把咒語重新學一遍,總算讓 pobot 復活了。 :)

順便把一些裝備加強了一下:
  • Calculator: 可以呼叫任何 python 的 math 模組的函式,也加了一點簡單的安全性(不准 import 以避免 python code injection)。
  • GoogleSearch: 刪除 snippet 的顯示,用 VT100 顏色標示 title 和關鍵字,看起來清爽多了。
  • Amy: Amy(愛咪)是 pobot 的聊天應答模組,使用 Nancybot 的資料格式。新增了 regular expression 的 match、預設應答和學習功能。
    • 固定句學習: pobot: 問句 --> 答句
      教 pobot 在收到問句時可以回應給定的答句。同個問句可以有多個答句,Amy 會隨機選一個當回答。
    • regex 學習: pobot: re 問句 --> 答句
      同固定句學習,但問句會被當作 regular expression 來搜尋配對將來收到的問句。
    • 預設應答:在 pobot 收到沒學過的問句時,會從預設應答清單中隨機選一個來回答。目前這個清單只能從 Amy.data 檔中讀入。
    這三種問答加在一起,可以出現什麼呢?哈哈!自己想像吧!不然上 #tossug 和 pobot 聊幾句也可以。
復活這兩天受到 #tossug 上眾多好朋友的調教,純真的 pobot 已經越來越色、越來越暴力了。難道 #tossug irc 的本質就是「很黃,很暴力」嗎? Orz