
工作終於努力到一個段落了
就這麼靜悄悄地跨過了一個門檻
沒有電影中打敗壞蛋,戰剩惡魔的欣喜若狂
似乎
一切未曾發生過。
****
看書,可以讓自己多點知識,少點寂寞。
好久沒有看一本書在一兩天內就看完的。
這本書不厚,書中的例子也很生活化,讀起來很輕鬆。
書中舉出很多人在做決策時的盲點,並且提出一些方式讓讀者可以試著去避免這些看似正常,但實則傻瓜的決定。
REF:
別人的心得,有一些書中的摘要
久等了,MadButterfly 終於和 Javascript 進行傳說中、超興奮的合體,這應該比智利礦工爬出礦坑還要振奮。而 Javascript Engine 百百種,可惜的是,我們這次沒有再為世界多加一種。我們選用 Google 的 V8 Javascript engine,理由當然是 V8 是藍星目前最快的 Javascript engine。單只有 Javascript engine 當然還不夠,還需要和 engine 配合的各種 library,於是我們選擇了 nodejs 做為整合的對象。 nodejs 是一個以 V8 為基礎的 server side 開發平台,雖然我們不執行在 ...

2010-7-20 參加 2010 營建管理研究會,並發表一篇論文「應用 HTML5 及版本控制技術提昇 Web-based 營建資訊管理系統使用效率之研究」,僥倖獲得評審青睞,拿到一張獎狀。
論文摘要:網路科技不斷創新,已經為各個領域帶來重大利益與產值提昇。然而,營建工業絕大部分的施工區,因屬於無法享受網路科技的郊外,這道先天上的屏障,使得營建業被詬病是『網路資訊科技應用』最落伍的產業,就算目前無線網路技術(如 3G 、 WiMAX 等)起步佈建,也很難改善大部份地區工程的網路使用率,而攸關品質管理所需之現地作業,無論如何增加營造廠總公司、監造單位、主辦機關內部辦公室的網路頻寬,也無法解決現今營建工區法利用網路科技的困境。目前的工地管理往往還是採用傳統紙張報表方式作業,造成品質管理效率低下及錯誤率高。
當前資訊管理應用系統的世界趨勢是朝向網頁應用程式靠攏,因為網頁應用程式可以跨平台,不需使用者作額外設定及安裝,介面也較傳統桌面應用系統具有親和力,所以過去以作業系統綁應用程式的情境不會發生在網頁應用程式中,網頁應用系統功能升級也不會困惱使用者,可以更方便地作到資料保全,網頁應用系統惟一的問題則是離開網路就無法發揮功用。
本研究利用最新 HTML5 標準技術結合軟體產業普遍應用之版本控制技術建置一個可在無網路環境下填寫的Total Web-based 營建資訊管理系統。藉由此『Total Web-based』技術,讓管理人員在無網路的工地環境中,仍可在電腦上作業,在回到有網路的辦公室環境中,可即刻進行資料同步整合至網頁伺服器並進行數據統合運算,避免重覆謄寫造成的錯誤,提高無紙化作業程度,降低人力成本。
全文 PDF 下載、簡報 PDF 下載。
昨天睡前心血來潮翻了一下《世紀末軟體革命復刻版》,這本我一直非常喜愛的經典書籍。(註)意外翻到書中提到Alan Kay在1970年代的Xerox PARC(Palo Alto Research Center)提出Dynabook概念的那段歷史:
曾經有好長一段時間,電腦給人的印象是處理複雜運算的龐然巨物,CPU龐大不說,磁帶機、終端機…硬體設備本身便以大著稱。這些「巨物」處理的事務也是龐大的:大量的數據、大量的資料…。電腦是不折不扣的資料處理機,和人們的生活其實是八竿子打不著邊的。
1969年,一位Ohio大學的研究生Alan Kay提出了一個構想:他希望創造一「本」可以帶著跑的電腦,並且利用電腦的資料儲存和運算能力,模擬甚至取代現有的紙跟筆。這台電腦的理想體積要和紙張的筆記本相近,能夠用它來從事寫作、繪畫、個人行程編排或是財務管理、通訊,或者是用它來取代傳統的教科書等「死板」的文字。
如果書本不再只是單向地灌輸知識,而是能對讀者的迴響做出反應(從最簡單的回答問題的正確到複雜的全文檢索等),甚至讓讀者也參與創作的過程(例如透過網路,作者可以和讀者交流,而在「筆記本」上的內容可以隨時更動),那麼我們所得到的,將是一個和當時截然不同的文化 – 對「電腦」的概念不同了,以往對「書本」、「資訊」的概念也將翻新。Kay把他理想電腦稱作Dyna Book,是「動態」的「書」,而不是xx computer,等於不再把電腦當做「電腦」了。
這段歷史我很久以前就知道了,但我一直以為Dyna Book的概念是更接近於筆記型電腦的東西。但昨天看到這段文字時,我卻有了完全不同的感覺,心裡異常的激動,因為這段文字描寫的Dyna Book,似乎更像另一個東西,一個直到今年才出現的東西。上網查了一下Alan Kay當初的論文,看到這圖我才明瞭,原來Dyna Book的設計根本就不是電腦!!
1968年Alan Kay的Dyna Book,其實就是2010年Apple iPad的原型啊。
看到這讓我不禁感嘆,1970年的Xerox PARC真是個傳奇性的研究單位,從以太網路(Ethernet)、最早的個人電腦Alto、圖型使用者介面(GUI)、物件導向程式設計(OOP)和第一個物件導向語言Smalltalk都是在這被發明出來的。(附帶一提,GUI、OOP、Smalltalk的發明人其實都是Alan Kay。)可是Xerox畢竟是個做影印機的公司,PARC做出了這麼多驚世發明,雖然跟影印機都沒關係,但不論哪一樣東西持續發展下去都大有可為,結果Xerox就這樣讓這些概念被Apple和Microsoft免費拿去創造了現今的電腦王國…。
但話說回來,即使在70年代Xerox就投下資源去做Dyna Book,結果也一定不會成功。對當時的環境來說,Dyna Book的概念實在太過先進,能實現這個產品的軟硬體技術都還不存在。除此之外,當時的電腦是只有大型企業或是尖端研究機構才會有的東西,大眾還沒辦法接受每個人都需要一台有「運算能力的機器」(computing device)這件事。即使到了1993年,那個個人電腦才剛開始普及的時代,Apple推出的Newton(最早被稱為PDA的機器,話說回來也還是想實現Dyna Book所描繪的遠景),最後也是慘淡收場。
商業界有本很有名的書叫「跨越鴻溝」(Crossing the Chasm)。這本書的核心概念是說一個新科技被接受的時間可以分為五個時期,過了最早的創新期後,要先讓一群對新科技比較敏感及狂熱的「早期接受者」(early adopters)接受後,再來才能大量擴張到「早期的主流大眾」(early majority)。但很要命的是在early adopters這個區域有一個巨大的鴻溝,如果一個創新的科技不能得到夠多early adopters的支持,就會直接跌落谷底而死亡。
Dyna Book在1968年前提出的概念,一直到2010年才真正實現並跨過鴻溝讓主流大眾接受。不知道該說是Alan Kay的思想超前時代太多,還是相關科技與大眾進步得太慢…。
但話說回來,從The iPad was invented 38 years ago一文所做的比較看來,iPad已經距離Dyna Book的願景非常接近了,但還是有兩點不是那麼容易解決的問題:第一,「Kay把Dyna Book視為一個創造並閱讀資訊的裝置,但iPad主要是設計為一個閱讀裝置。」第二,「使用者要能在這個裝置上創造他們自己的程式。」
很有趣的是,這兩點都是人機互動上的難題。40年來,硬體技術的成長把iPad變得又輕又薄又帶有非常強大的運算能力,但在軟體的使用介面上一直還是沒有很大突破。尤其是讓每個使用者都有能力寫他們自己的程式(end-user programming),更像一個終極的聖杯,能徹底解放人類使用機器的自由,但到底該怎麼做卻沒人有頭緒。(註二)
寫到這裡,不禁擔心起來,如果Alan Kay在40年前提出的概念到今天才開始要進入early majority的普及程度,那麼到現在都還沒有出現的end-user programming聖杯,究竟要多少年後才能真正普及到全人類手上呢?
註:《世紀末軟體革命》由劉燈、賀元、賴明宗所著,這三人都是台灣資訊界早期的傳奇人物。這本書有三個版本,1994年的第一版,1996的第二版,2006又出了復刻版。這本書是中文電腦書中難得一見能把物件導向和GUI相關架構與理論概念完全融會貫通再加以清晰闡述的書。如果有心想融會貫通物件導向與GUI系統核心概念的人,這本書真的值得一看再看。
註二:Alan Kay所描繪的Dyna Book主要使用者是小孩,所以說如果是以讓小孩子能創造自己的程式為目標的話,MIT Media Lab的Scratch可以說是一個很成功的里程碑。(Scratch用「積木」來寫程式的概念在今年被Google做成了App Inventor for Android,可以用同樣的方式寫Android程式。)(雖說是打Google的招牌,但其實App Inventor是MIT CSAIL教授Hal Abelson去年輪休時去Google做的。)
後記:
很多人說iPad是抄襲Dyna Book的概念,這點其實很難說得清楚到底是抄襲或是「實現共同的願景」,畢竟Dyna Book是40年前的提出的概念了。但Apple在iPad出來後不久就拒絕了Scratch的iPad app,原因是Apple不想要使用者能藉由第三方的平台來執行程式,否則使用者就可以繞過App Store取得其他軟體了(Flash主要也是因為同樣的原因被封殺)。這個決定可以看出Apple並不是想做Dyna Book,而是一個一定要先繳錢成為會員後才能開發程式的…….i板子。
針對非線性迴歸求解其係數值,我寫了一份文件,考慮了其中繁雜的數學,我是用 rst 格式撰寫,配合 latex 轉成 PDF 。因為要轉 html 時,那些數學式實在是太麻煩了,所以我想就只提供 PDF, rst 給各位下載。
本文件用途說明:
當我們有一堆觀測數據,想要找出一條方程式可以將自變數、應變數的關係明確表示時,可以使用 least square method 求解,例如我們有 10 個觀察值(1, 4), (4, 5), (1, 2), (4, 5), (6, 9), (1, 8), (4, 5), (3, 4), (5, 5), (6, 6) 等,而我們先猜測它們的關係是二次的,應該要符合 Y = a * X^2 + b * X + c 方程式,有了觀測值及預估方程式形式後,接下來就可以利用 least square method 計算出 a, b, c 三個係數,期使它們能讓計算出來的 Y 值與觀察值的誤差最小。
在求取 a, b, c 三個係數上,我介紹了 4 種方法: the steepest descent method, Newton's method, the Guass-Newton method 和 levenberg-marquardt method 。
PDF表文下載
rst全文下載
** 以下純供搜尋引擎使用,生人勿近 **
應用問題說明
--------------------------------------------------------------------------------
當我們有一堆觀測數據,想要找出一條方程式可以將自變數、應變數的關係明確表示時,
可以使用 least square method 求解,例如我們有 10 個觀察值
(1, 4), (4, 5), (1, 2), (4, 5), (6, 9),
(1, 8), (4, 5), (3, 4), (5, 5), (6, 6) 等,
而我們先猜測它們的關係是二次的,應該要符合 :math:`$Y = a \times X^2 + b \times X + c$` 方程式,
有了觀測值及預估方程式形式後,接下來就可以利用 least square method 計
算出 :math:`$a$`, :math:`$b$`, :math:`$c$` 三個係數。
評估非線性方程式的係數值
--------------------------------------------------------------------------------
假定一含有 :math:`$n$` 個未知係數的
方程式 :math:`$E(x_1, x_2, ..., x_k, p_1, p_2, ..., p_n)$` ,
在 :math:`$m$` 組觀測值
(:math:`$(y_1, x_{11}, ..., x_{1k})$`, :math:`$(y_2, x_{21}, ..., x_{2k})$`, ..., :math:`$(y_m, x_{m1}, ...x_{mk})$`) 下,
欲求出此 :math:`$n$` 個係數的值,
期使 :math:`$E(x_1, x_2, ..., x_k, p_1, p_2, ..., p_n)$` 與觀測值的誤差最小。
首先定義理論值與觀測值的誤差如式 :ref:`\ref{errors define}` 的 :math:`$f_i$` 。
.. raw:: latex
\begin{equation}\label{errors define}
f_i(p_1, p_2, ..., p_n) = y_i - E(X_i, p_1, p_2, ..., p_n), i \in 1, ..., m
\end{equation}
\begin{equation}\label{F function}
F(p_1, p_2, ..., p_n) = \sum_{i=0}^{m} (f_i(p_1, p_2, ..., p_n))^2, m \geq n
\end{equation}
將每一觀測值誤差平方並加總起來,可得到一目標函式 :math:`$F$` 其定義如式 :ref:`\ref{F function}` 。
當 :math:`$ F $` 函式的值為全域最小值或是區域最小值,
其特定 :math:`$ [p_1^*, p_2^*, ..., p_n^*] $` 組合,
也就是 :math:`$P^*$` ,即為該 :math:`$ E $` 函式的係數全域或區域最佳解。
所有的非線性最佳化都是用迭代方法計算的:
從一個起點 :math:`$P_0$` 開始搜尋,產生一系列的向量 :math:`$P_1, P_2, ..., $` ,
希望可以收斂至一個 :math:`$ P^{*} $` ,使得函式成為全域或區域
最佳解 :cite:`\cite{k_madsen_imm_2004}` 。
.. raw:: latex
\begin{equation}\label{Taylor expansion}
F(P_{k+1}) = F(P_k) + h^{\top} {F}'(P_k) + \frac {1}{2} h^{\top} {F}''(P_k) h + O(||h||^3)
\end{equation}
\begin{equation}
h = P_{k+1} - P_k
\end{equation}
如式 :ref:`\ref{Taylor expansion}` ,首先以 Taylor expansion 改寫 :math:`$ F $` 函式,
:math:`$O(||h||^3)$` 代表後面無窮盡的項目,
:math:`$ k $` 代表的是第幾次 iteration 。在每次 iteration 中,
我們先找出 :math:`$ h $` ,使得 :math:`$F(P_{k+1}) < F(P_k)$` 。
目前常見計算 :math:`$h$` 的逼近法有 The Steepest Descent method,
Newton's method, Guass-Newton method, The Levenberg-Marquardt method。
The Steepest Descent method
********************************************************************************
Steepest Descent method 將式 :ref:`\ref{Taylor expansion}` 改寫
為式 :ref:`\ref{Taylor expansion2}` ,忽略二階以後項目。
.. raw:: latex
\begin{equation}\label{Taylor expansion2}
F(P_{k}+\alpha h) \simeq F(P_k) + \alpha h^{\top} {F}'(P_k), \alpha > 0
\end{equation}
而原來的 h 改寫成一個純量 :math:`$\alpha$` 再乘以向量,這樣在 :math:`$P_{k+1}$` 接
近 :math:`$P^{*}$` 時, :math:`$\alpha$` 必定近似 0 ,
所以我們又可以得到式 :ref:`\ref{steepest descent}` ,
.. raw:: latex
\begin{equation}\label{steepest descent}
\lim_{\alpha \to 0} \frac{F(P) - F(P + \alpha h)}{\alpha \left \| h \right \|}
= - \frac{1}{\alpha \left \| h \right \|} h^{\top} {F}'(P)
= - \frac{h^{\top}}{\alpha \left \| h \right \|} \frac{{F}'(P)}{\left \| {F}'(P) \right \|} \left \| {F}'(P) \right \|
= - \left \| {F}'(P) \right \| cos \theta
\end{equation}
:math:`$\alpha \left \| h \right \|$` 為純量,所以我們
希望 :math:`$F(P)-F(P+\alpha h)$` 的值愈大愈好,
這樣 :math:`$ cos \theta $` 就必須為 -1 ,
而 :math:`$cos \theta$` 是 :math:`$h$` 與 :math:`${F}'(P)$` 的夾角,
所以如式 :ref:`\ref{sd}` ,最佳的 :math:`$h_{sd}$` 必為 :math:`$-{F}'(P)$` 。
.. raw:: latex
\begin{equation}\label{sd}
h_{sd} = - {F}'(P)
\end{equation}
如式 :ref:`\ref{sd}` ,陡降法中的 :math:`$h_{sd}$` 是以斜率值負值為移動方向。
而 :math:`$\alpha$` 的值,
我們需用 line search 求得,但效率通常會是個問題,所以也可以使用 binary search 方式來求得,
其概念是先取得一個 :math:`$\alpha_{min}$` 值讓 :math:`$F(P)-F(P+\alpha h)$` 大於 0 ,
再取得一個 :math:`$\alpha_{max}$` 值讓 :math:`$F(P)-F(P+\alpha h)$` 小於 0 ,
接下來以 :math:`$\frac{1}{2}(\alpha_{min} + \alpha_{max})$` 為
新的 :math:`$\alpha_{middle}$` 值,
去計算 :math:`$F(P)-F(P+\alpha h)$` 是大於 0 還是小於 0 。若大於 0 ,則
新的 :math:`$\alpha$` 值
應為 :math:`$\frac{1}{2}(\alpha_{middle} + \alpha_{max})$` ,若小於 0 ,則新
的 :math:`$\alpha$` 應為 :math:`$\frac{1}{2}(\alpha_{middle} + \alpha_{min})$` ,
如此迭代計算後,當 :math:`$\alpha$` 滿足預設條件或達迭代次數即可決定。
Newton's method
********************************************************************************
牛頓法則考慮以 :math:`$ F $` 函式的二階 Hessian 矩陣來計算 h 。
它將式 :ref:`\ref{Taylor expansion2}` 再取其一次微分得到
式 :ref:`\ref{Taylor expansion for newton}` ,若 :math:`$(P_k + \alpha h) = P^{*}$` ,
則 :math:`${F}'(P_k + \alpha h )$` 必等於 0 。
.. raw:: latex
\begin{equation}\label{Taylor expansion for newton}
{F}'(P_{k}+\alpha h) \simeq {F}'(P_k) + \alpha h^{\top} {F}''(P_k), \alpha > 0
\end{equation}
所以我們可以得到式 :ref:`\ref{newton}` ,而 :math:`$h_{n}$` 就等於
式 :ref:`\ref{newton2}` 定義。
.. raw:: latex
\begin{equation}\label{newton}
0 = {F}'(P_k) + \alpha h^{\top} {F}''(P_k)
\end{equation}
.. raw:: latex
\begin{equation}\label{newton2}
h_{n} = - \frac{{F}'(P)}{\alpha {F}''(P)}
\end{equation}
在搜尋效率上,牛頓法為二元收斂,而陡降法為線性收斂,所以牛頓法在接近最佳解時比較快,
而陡降法則是離最佳解較遠時比較快,且因 Hessian matrix 在計算上
不一定為 positive definite ,所以牛頓法往往會混合陡降法來實作。
The Guass-Newton method
********************************************************************************
Least squares problems 一般能用陡降法或是牛頓法求解,但要追求效率的話,我們應該作部份調整。
像是盡量使用二元收斂或是不需實作出 :math:`$F$` 函式 :cite:`\cite{k_madsen_imm_2004}` 。
我們將式 :ref:`\ref{Taylor expansion}` 的 :math:`$F$` Taylor expansion 改使用
在 :math:`$f$` 上,如式 :ref:`\ref{f Taylor expansion}` 。
.. raw:: latex
\begin{equation}\label{f Taylor expansion}
f(x + h) = f(x) + J(x) h + O(||h||^2)
\end{equation}
\begin{equation}
(J(x))_{ij} = \frac{\partial f_i}{\partial x_j}(x) = {f}'(x)
\end{equation}
式 :ref:`\ref{f Taylor expansion}` 可再整理為式 :ref:`\ref{f Taylor expansion2}` 。
.. raw:: latex
\begin{equation}\label{f Taylor expansion2}
f(x + h) \simeq l(h) \equiv f(x) + J(x) h
\end{equation}
\begin{equation}\label{new F Taylor expansion}
F(x + h) \simeq L(h) \equiv \frac{1}{2}l(h)^{\top}l(h)
= \frac{1}{2}f^{\top}f + h^{\top}J^{\top}f + \frac{1}{2}h^{\top}J^{\top}Jh
\end{equation}
再將式 :ref:`\ref{new F Taylor expansion}` 對 h 作一次微分得到式 :ref:`\ref{gn function}` 。
.. raw:: latex
\begin{equation}\label{gn function}
{L}'(h) = J^{\top}f + J^{\top}Jh
\end{equation}
因為在最佳解時, :math:`${L}'(h)$` 等於 0 ,所以我們可以得到 :math:`$h_{gn}$` 如
式 :ref:`\ref{guass-newton}` 。
.. raw:: latex
\begin{equation}\label{guass-newton}
h_{gn} = - \frac{J^{\top}f}{J^{\top}J}
\end{equation}
The Levenberg–Marquardt method
********************************************************************************
The Newton's method may not be defined beacause of the singularity of
:math:`$ {F}''(P_k) $` at
a given point :math:`$ P_k $` , or the search direction :math:`$ h_n $`
may not be a descent direction
:cite:`\cite{bazaraa_nonlinear_2006}` .
The algorithm used the gradient methods their ability to converge from an
initial guess which may be outside
the region of convergence of other methods. The algorithm uses the Taylor
series method the ability to close
in on the converged values rapidly after the vicinity of the converged
values has been
reached. Thus, The method combines the best features of its predecessors
while avoiding their most serious
limitations. :cite:`\cite{marquardt_algorithm_1963}` .
Levenberg-Marquardt 方法乃加入一 damping parameter :math:`$ \mu $` 。
.. raw:: latex
\begin{equation}
h_{lm} = - \frac{J^{\top} f(P)}{J^{\top} J + \mu I}, J = {f}'(P), I = Identity\ Matrix
\end{equation}
此自定參數的效益在於,For all :math:`$ \mu > 0 $` the coefficient matrix is positive
definite,
and this ensures that :math:`$h_{lm}$` is a descent direction. For large
values of :math:`$ \mu $` we get
.. raw:: latex
\begin{equation}
h_{lm} \simeq - \frac{1}{\mu}{F}'(P)
\end{equation}
If :math:`$ \mu $` is very small, then :math:`$ h_{lm} \simeq h_{gn} $` ,
which is a good step in the
final stages of the iteration, when P is close to :math:`$ P^{*} $` .
If :math:`$ F(P^{*})=0 $` (or very small),
then we can get (almost) quadratic final convergence :cite:`\cite{k_madsen_imm_2004}` .
:math:`$\mu$` 值在每個 iteration 中,皆不同,而 :math:`$ \mu_{k} $` 的選擇,
主要有兩種方法,
一是看 :math:`$J(P_{k})^{\top} J(P_{k}) $` 中,
對角線元素中最大值再乘以 :math:`$ \gamma $` ,
一般來說, :math:`$\gamma$` 的值介於 :math:`$ 10^{-6} \sim 1 $` 之間。
或是也可以用 :math:`$ F(P_{k}) - F(P_{k-1}) $` 的值 :math:`$s_{k}$` 來判斷,
當 :math:`$ s_k \geq 0 $` 時
, :math:`$ \mu_k $` 增加 10 倍,
當 :math:`$ s_k \le 0 $` 時, :math:`$ \mu_k $` 減少 10 倍,
:math:`$ \mu_0 $` 的初始值則是設為 0.001 。
小結
--------------------------------------------------------------------------------
理論上,非線性最佳化是沒辦法求得全域最佳解的,就算你運氣真的很好,
瞎貓怕上死耗子,讓你遇到全域最佳解,但你還是沒有辦法去驗證它的確是全域最佳解。
所以,以上介紹的 4 種找尋 h 的方法,都只是一種有系統的找尋技巧,這些方法經過數學推導,
可算是比較有效率罷了,不代表只有這些方法可以用在 least square problem 上。
你也可以任意混合這 4 種方法,如在第 1 ~ 10 次迭代時,使用陡降法,在第 11 ~ 20 次時,
使用 Levenberg-Marquardt 方法,在第 20 次以後一律使用高斯-牛頓法,
這種方法是沒有對錯的,只有解題時間的快與慢而已,而這快與慢就又牽扯到起始值的挑選及非線性函式的特性。
這次這樣用比較快,不表示這對其他問題的解題速度就會比較快。
References
[1] M. S. Bazaraa, Hanif D. Sherali, and C. M. Shetty. Nonlinear programming. John Wiley
and Sons, 2006.
[2] K. Madsen, H. B. Nielsen, O. Tingleff, and Mathematical Modelling. IMM METHODS
FOR NON-LINEAR LEAST SQUARES PROBLEMS, 2004.
[3] Donald W. Marquardt. An algorithm for Least-Squares estimation of nonlinear parameters.
Journal of the Society for Industrial and Applied Mathematics, 11(2):431–441, June 1963.
ArticleType: primary_article / Full publication date: Jun., 1963 / Copyright 1963 Society
for Industrial and Applied Mathematics.
在體能可以慢跑 3 公里後,我時常會跑到食指指甲瘀青、變形。而這次則在跑了 12 公里後,造成我的左腳指甲剝離流血,上圖是右腳指甲的狀況,我想左腳相片就不給各位看了,會讓你們吃不下飯的。
本來,我一直認為是慢跑鞋的問題,因為它的腳趾空間不夠多,在跑步時指甲會一直摩擦到鞋頭。現在的慢跑鞋是 Brooks Trance 6 ,非常喜歡這一雙鞋,嚴格說來,應該是這一雙鞋讓我愛上慢跑的。它是我第一雙真正的慢跑鞋,過去我都是穿迪亞多那的休閒鞋來慢跑的,當我第一次穿著 Trance 6 跑步時,我感覺到「工欲善其事,必先利其器」的意義。它的避震效果十分好,讓我的腳底板沒那麼痛,增大了我的跨步步幅,它的好,使得我又買一雙。
不過,今天我終於下定決心要換一雙慢跑鞋了,畢竟指甲剝落不是小事。首先我 google 「如何挑選不會讓腳指瘀青的慢跑鞋」,才發現,這問題不在鞋子,而是出在我的鞋帶綁法。
之前我為了登山,有買了一雙登山鞋,老闆有跟我說明為了在下坡時,不要讓腳指甲往前衝到鞋頭,所以要在高統部份將鞋帶綁緊,而鞋頭部份的鞋帶可以不用這麼緊。這個方法我也延用到慢跑鞋上,習慣上,我都是前頭比較鬆、後頭比較緊,然而這畢竟是慢跑鞋,跑在下坡時的衝擊力比登山下坡的力道還大,跑久了前頭的線會慢慢往後頭鬆去,於是我的腳掌就開始自由地在鞋內移動了,指甲也就瘀青了。
所以,只要綁緊鞋帶,指甲就不會瘀青了,不用換鞋子。

之前聽同事說,Toy Story在IMDB上的評價高得誇張,有到9點多。後來看了,覺得這部電影真的做得很好。儘管是第三部了,故事內容並不會讓人覺得太過無趣;動畫的效果也是愈來愈細緻。看3D的話,應該會很感動吧。第一集中的小男生,終於長大成人,面臨著要把兒時伴他成長的玩具們送出的決定。小男孩的表情,不論是眉毛、眼神、嘴巴,都幾乎跟真人在表達情感時會有的線條差不多了。玩具的話,那隻惡熊的皮毛也跟真的玩具差不多。之後的動畫,不曉得還可以怎樣再發展下去呢?
****
抽屜中的情書:常盤貴子演的一部小品。全片中除了常盤貴子之外,應該都是小咖吧。故事場景主要是在東京鐵塔附近,常盤貴子扮演一個電台節目的主持人;還有其中一個故事主軸是在北海道的函館。很多小故事,被一個廣播節目特輯串了起來。透過廣播的方式,讓許多人得以說出心聲。
以前國中唸書時,偶爾也會聽聽類似的節目。長大之後,隨著電視、網路的流行,廣播已經漸漸從生活中淡出,只剩下純音樂的網路電台。人和人之間的感覺,似乎愈來愈遠了。
REF:
http://hiki-koi.com/

上車,果然沒有事先訂票的結果就是:No Seat。
台中火車站內,發現好玩的系統:微型自助圖書館。台中市民可以在這個類似販賣機的書架前選自己想借的書。在裡頭看到了幾本自己也想借來翻翻的書,可惜我不行借。
在台中火車站旁的旅遊中心,問了怎麼去高美溼地。櫃台小姐很好心地寫了一張紙條給我,在完全沒有地圖的情況下,把路線跟我說了一次。
免費的地圖上,在台中市區內畫了很多塊商圈,因為天氣很悶熱,所以就先到美術館逛逛。美術館的正面上方,有目前正在展覽的大型海報,正面下方是大片大片的落地窗,大量的光線將大廳照得很亮。
美術館大廳在展覽的是不二良的作品。很多知名角色都被整合進這些大型公仔中。依序是原子小金鋼、小叮噹、蝙蝠俠、藍色小精靈、地獄怪客和Hello Kitty。
最後一個是比較大型的瑪莉兄弟。
還有M&M造型的小公仔。

美術館很大,在展覽的主題也很多。比較有印象的是數位之手,裡頭有不少限制級或是比較灰暗的作品;典藏抽象繪畫展的話,沒有辦法讓我有很大的感觸;書法展,裡頭有很多蠻喜歡的作品,不知道iPad是不是也可以出個寫毛筆的軟體,讓我隨時可以再練習一下;日本版畫展。

在二樓展區外,放置了好幾個像是沙發的東西。仔細一看,一片一片的東西實際上是紙,由於很緊密地排列在一起,所以當人坐在上頭時,不會整個凹下去。除了很特別之外,還可以隨心所欲地改變它的形狀或是收起來。
要出美術館時,差點就錯過了一區很有特色的展覽。這是一個疊滿知名品牌的十字架。沒有仔細看它的說明,我自己的解讀是,人的身上被各式各樣的物慾所束縛著,它就像是個沉重的十字架一樣。

除了拿品牌來當十字架外,還有一系列的球鞋恐龍。遠遠看到時,並沒有覺得很特別,想說到處都看得到這類的恐龍化石照,但是近看才發現,球鞋的圖案已經被巧妙地融合在一張又一張恐龍裡。很佩服作者的創意。果然,藝術不光只是把一幅圖畫好而已,在裡頭還要注入許多個人的想法和創意,才能讓自己的作品不會過於膚淺。

該脫鞋了。事前沒想到要涉水這回事,穿了皮鞋出門。管它的,就脫吧。反正那麼舊了,也不會有人想要撿去。仔細看,台灣人還是很乖的。脫下來的鞋子,大都整整齊齊地排列在道路的兩旁。
才剛踩到水裡,就看到水面上的小洞有小螃蟹跑來跑去。他們也是要出來看夕陽的嗎?
高美溼地比想像中還要遠。雖然路程在一小張小紙片上就可以講完,但是實際上還是花了不少時間。還好在太陽下山前趕到了,來得及拍個幾張照片。
還是大自然比較能夠讓我放鬆心情。
金黃色的水面,好溫暖。
將白平衡調至螢光燈,偏紫色的天空馬上出現。有時雲層比較薄,會露出點藍天。遠方可以看到不少人在拍照或是走動,為水平線增加了一點律動。腳邊薄薄地一層水漬,也很配合地反射出天空的各種顏色變化。
望左邊看去,是一整排的風力發電桿子。今天只帶了GRD出門,沒辦法拍特寫,只好就這麼遠遠地拍張照留念。
站在海邊往岸上看,有一根像是燈塔的建築,紅白相間。搭配上一大片濃厚的烏雲,令人有種淒涼孤單的感覺。明明看著落日時,是那麼地溫暖;一回頭卻是如此蕭瑟。
從高美溼地回市區時,碰巧看到夜景。在大馬路旁往下望就是一條銀河狀的燈海。儘管我不是那麼愛夜景的人,也不禁多看了兩眼。

逢甲夜市人很多,幾乎每一攤都有人在排隊。有的還排得有夠誇張。要我排那麼久的隊,想吃東西的心情應該都會被磨光吧。
沒有好好做行程規劃的下場就是:沒車坐。回台北的火車,最後一班是八點多還是九點多。在逢甲夜市人擠人一番之後,自然是沒坐到最後一班車。好在,車站旁還有客運可以搭,不至於流落街頭。只是,客運好像會繞路,開了很久才到台北,害我回台北後,還得再坐計程車。
周日下午臨時起意從埔里騎到台中,去回總路程約 106 公里。 1:30 出發,約在 2:50 到霧峰的一家 7-11 ,位置在立法院中部辦公室(原省議會)到霧峰農工之間,在 3:30 到達中興大學。
因為出發時,天空有點飄雨,也就沒帶著 GPS 紀錄器及手機,幸好到了研究室,有學弟帶了數位相機,把我這難得的疲態拍下來。從埔里到台中這段路還滿好騎的,畢竟下坡比較多,只有在烏溪橋遇到了大雨,比較辛苦外,路程還算輕鬆。
View 埔里 <=> 台中 by 自行車 in a larger map
下面是折返點的相片,我在研究室待了近 1 個小時,主要是等我的襪子乾,學弟建議我使用粉紫塑膠袋來作鞋子雨衣。套上後,感覺是可以防水,但我沒有勇氣這樣騎在路上。
還好回途中,沒有再下雨了。我在 4:30 出發, 5:30 在草屯療養院附近的 7-11 用晚餐, 6:00 繼續上路。最後,到家時間是晚上 8 點了。
總共騎乘時間是 5 個小時,考量道路情況,下次應該在上午就得出發到台中,才不會晚上回埔里時,沒有路燈,而自行車照明設備又不像汔車車燈一樣又亮又遠,騎快的話,有點可怕。
根本就沒有這個比賽。
程式的執行單位 - 迭代的方案 利用遞迴的計算方式解決問題比較直覺,但是當計算的值越大時,所需的時間也就越多。其實遞迴的方法都能夠用迭代的計算方式來代替,所謂的迭代類似公式解,利用一個迴圈進行計算工作,因此不會消耗太多的記憶體,得到結果的時間也會快很多。 迭代的方案雖然有其優點,問題是迭代並非顯而易見的,例如計算階層數,我們該怎麼把計算都濃縮在一個迴圈之中呢? 因為每一個階層數都是從 1 開始相乘,因此我們可以設定迴圈變數 i 從 1 開始遞增,然後另外用一個儲存算結果的變數 result ,把 result 乘上每一個遞增的 i 。 基於這個想法,程式如下 #include <stdio.h> int factorial(int n); int main(void) { int i; for (i = 0; i < 10; i++) {
程式的執行單位 - 遞迴函數 數學上的數列是按順序排列的數字,有些數列採取遞迴定義,所謂的遞迴是說數列中的數字可由前幾項計算出來,例如費伯納西數列由 0 和 1 開始,往後的數字都由前兩項相加,形成如下的數列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, .... 我們也能將利用遞迴的計算方式寫進程式中,例如,計算以上的費伯納西數列 #include <stdio.h> int fabonacii(int n); int main(void) { int i; for (i = 0; i < 16; i++) { printf("%d ", i, fabonacii(i)); } printf("\n"); return 0; } int fabonacii(int
程式的執行單位 - 使用區域變數的帳號管理程式 編譯執行 編譯執行,顯示登入畫面後 新建幾個帳號 以管理員的帳號、密碼登入 輸入 list 指令 輸入 delete 指令,刪除掉 bill 再次輸入 list 指令,查看刪除後的列表 輸入 sort 指令,進行排序 輸入 list 指令,查看排序後的列表 輸入 exit 指令,離開管理模式 重新以管理員帳號登入 再次輸入 exit 指令,結束程式 程式的執行單位 印出提示訊息與顯示現在時間 四則運算器的函數版本 數字對調 線性搜尋的函數版本 範例程式與編譯執行氣泡排序的函數版本 範例程式與編譯執行處理時間的函數 範例程式與編譯執行1 範例程式與編譯執行2回傳指向結構的指標 範例程式與編譯執行1 範例程式與編譯執行2變數的儲存類型 範圍規則 使用全域變數的帳號管理程式
程式的執行單位 - 使用區域變數的帳號管理程式 現在我們採用另一個把帳號管理程式模組化的方式,這個版本將採區域變數的設計方式,也就是說,會把兩個二維字元陣列宣告在所有函數 main() 的定義之中 // 在所有函數外宣告預設的帳號及密碼 char userID[SIZE][LEN]; char userCODE[SIZE][LEN]; 同樣的,我們會定義如下各個函數 // 函數原型的宣告 int manage(int counter, char id[][LEN], char code[][LEN]); void printList(char id[][LEN], char code[][LEN]); void si(char id[][LEN], char code[][LEN]); int ssearch(char array[][LEN], int size, char *
程式的執行單位 - 使用全域變數的帳號管理程式 編譯執行 編譯執行,顯示登入畫面後 新建幾個帳號 以管理員的帳號、密碼登入 輸入 list 指令 輸入 delete 指令,刪除掉 bill 再次輸入 list 指令,查看刪除後的列表 輸入 sort 指令,進行排序 輸入 list 指令,查看排序後的列表 輸入 exit 指令,離開管理模式 重新以管理員帳號登入 再次輸入 exit 指令,結束程式 程式的執行單位 印出提示訊息與顯示現在時間 四則運算器的函數版本 數字對調 線性搜尋的函數版本 範例程式與編譯執行氣泡排序的函數版本 範例程式與編譯執行處理時間的函數 範例程式與編譯執行1 範例程式與編譯執行2回傳指向結構的指標 範例程式與編譯執行1 範例程式與編譯執行2變數的儲存類型 範圍規則 使用全域變數的帳號管理程式
程式的執行單位 - 使用全域變數的帳號管理程式 範例程式 #include <stdio.h> #include <string.h> #define SIZE 100 #define LEN 20 enum state {EXIT, RUN, WRONG_NAME, WRONG_CODE, Y, N}; // 函數原型的宣告 int manage(int counter); void printList(void); void si(void); int ssearch(char array[][LEN], int size, char *target); int di(int counter); int so(void); void ssort(char array[][LEN], char code[][LEN], int size); //
程式的執行單位 - 使用全域變數的帳號管理程式 現在我們來把帳號管理程式模組化,這個版本將採全域變數的設計方式,也就是說,會把兩個二維字元陣列宣告在所有函數的定義之外 // 在所有函數外宣告預設的帳號及密碼 char userID[SIZE][LEN]; char userCODE[SIZE][LEN]; 我們會定義如下各個函數 // 函數原型的宣告 int manage(int counter); void printList(void); void si(void); int ssearch(char array[][LEN], int size, char *target); int di(int counter); int so(void); void ssort(char array[][LEN], char code[][LEN], int size); 函數
程式的執行單位 - 範圍規則 自動型變數在程式中有一定的效力範圍,通常效力範圍是指用大括弧 { } 圍起來的程式區塊。宣告在所有函數外的變數,所有函數均可使用,但是一旦函數中宣告相同名稱的變數,就只能使用函數內所定義的變數了。 下例說明範圍規則的使用 #include <stdio.h> void test1(void); void test2(void); int a = 0; int main(void) { int a = 1; printf("a = %d\n", a); test1(); test2(); printf("\n"); { int a = 2; printf("a = %d\n", a); test1(); test2(
程式的執行單位 - 變數的儲存類型 變數,也就是識別字,我們已經見過許多例子,例如取得迴圈變數、儲存結果的變數、接受使用者輸入的變數,或是利用 #define 定義的常數、利用 enum 定義的列舉數,或是自行定義的函數名稱,這些全都是屬於識別字。 常數、列舉數定義後直接是常數值,函數屬於功能模組,我們已經陸續討論過不少函數的參數及回傳值,現在,我們把焦點集中在通常定易於函數中的識別字,也就是變數。 每一個變數都有型態、名稱及所儲存的數值,除了這些,變數還有儲存類型、佔用期間、範圍、連結等特性,如下 特性說明 儲存類型分為自動型及靜態型,自動型的變數在離開所屬範圍後,資料就會被銷毀,靜態型則會保留原值 佔用期間變數可被使用的有效期限,有些只存在一下子,有些反覆的被建立、刪除,有些能保存到程式執行結束 範圍變數能夠被使用的區域 連結分成內部連結及外部連結,









