linux2021
目的: 檢驗學員對數值處理, Linux 行程, hash table 的認知
1
在第 3 週作業 fibdrv 中,談及 arbitrary-precision arithmetic (即「大數運算」),以下是另一個實作方式,用二進位來表示和處理內部數值,考慮階乘 (factorial) 運算:
需要注意的是,這個實作不處理十進位數值輸出,預期 的輸出為十六進位表示法:
1b30964ec395dc24069528d54bbda40d16e966ef9a70eb21b5b2943a321cdf10391745570cca9420c6ecb3b72ed2ee8b02ea2735c61a000000000000000000000000
我們可透過 Python 內建的大數運算來檢驗: (執行 $ python3
後,在命令提示中輸入以下敘述)
以下是對應的大數運算實作程式碼,針對 little-endian 的機器,並以 x86_64
架構為主要測試標的:
作答區
COND = ?
(a)
if (res == tmp)) break
(b)
/* no operation */
(c)
if (!(res > tmp)) break
(d)
if (res > tmp) break
III = ?
(a)
UTYPE intermediate = a->array[i] * b->array[j]
(b)
UTYPE_TMP intermediate = a->array[i] * b->array[j]
(c)
UTYPE_TMP intermediate = a->array[i] * (UTYPE_TMP) b->array[j]
(d)
UTYPE intermediate = (UTYPE_TMP) a->array[i] * b->array[j]
(e)
UTYPE_TMP intermediate = a->array[i] + b->array[j]
延伸問題:
2
LeetCode 編號 1 的題目 Two Sum,貌似簡單,作為 LeetCode 的開篇之題,乃是經典中的經典,正所謂「平生不識 Two Sum,刷盡 LeetCode 也枉然」,就像英語單詞書的第一個單詞總是 Abandon 一樣,很多沒有毅力堅持的人就只能記住這一個單詞,所以通常情況下單詞書就前幾頁有翻動的痕跡,後面都是嶄新如初,道理不需多講,雞湯不必多灌,明白的人自然明白。
以上說法取自 Two Sum 兩數之和
mint condition: "mint" 除了薄荷的意思,還可指鑄幣廠,"mint condition" 裡的 “mint” 就與鑄幣廠有關。有些人收集錢幣會在錢幣剛開始發行時收集,因爲這樣的錢幣看起來很新,他們會用 "mint condition" 來形容這種錢幣的狀況,強調「像剛從鑄幣廠出來」,後來衍伸出「有如新一樣的二手商品」的意涵。
題意是給定一個陣列 nums
和一個目標值 target
,求找到 nums
的 2 個元素相加會等於 target 的索引值。題目確保必為單一解,且回傳索引的順序沒差異。例如給定輸入 nums = [2, 7, 11, 15]
, target = 9
,相加變成 9
的元素僅有 2
及 7
,因此回傳這二個元素的索引值 [0, 1]
考慮以下 C 語言實作:
提交到 LeetCode 線上評分系統,得到以下回應:
沒拿到 PR=99,心有不甘!想辦法改進。
若用暴力法,時間複雜度為 ,顯然不符合期待。我們可改用 hash table (以下簡稱 HT
) 記錄缺少的那一個值 (即 target - nums[i]
) 和對應的索引。考慮以下案例:
nums =
[2, 11, 7, 15]
:
對應的步驟:
nums[0]
是 2
,HT[2]
不存在,於是建立 HT[9 - 2] = 0
nums[1]
是 11
, HT[11]
不存在,於是建立 HT[9 - 11] = 1
nums[2]
是 7
,HT[7]
存在 (設定於步驟 1
),於是回傳 [2, HT[7]] = [2, 0]
hlist
用於 hash table 的實作,它的資料結構定義在 include/linux/types.h 中:
示意如下:
hlist
的操作與 list
一樣定義於 include/linux/list.h,以 hlist_
開頭。hlist_head
和 hlist_node
用於 hash table 中 bucket 的實作,具有相同 hash value 的節點會放在同一條 hlist
中。 為了節省空間,hlist_head
只使用一個 first
指標指向 hlist_node
,沒有指向串列尾節點的指標。
以下是引入 hash table 的實作,學習 Linux 核心程式碼風格:
作答區
NNN = ?
(a)
/* no operation */
(b)
n->pprev = first
(c)
n->next = first
(d)
n->pprev = n
PPP = ?
(a)
n->pprev = &h->first
(b)
n->next = h
(c)
n->next = n
(d)
n->next = h->first
(e)
n->next = &h->first
延伸題目:
GOLDEN_RATIO_PRIME
,探討其實作考量3
user-level thread 又稱為 fiber,設計動機是提供比原生執行緒 (native thread) 更小的執行單元。我們嘗試透過 Linux: 不僅是個執行單元的 Process 和 UNIX 作業系統 fork/exec 系統呼叫的前世今生 提到的 clone 系統呼叫,來實作 fiber。
給定以下程式碼:
預期執行輸出如下: (其中一種可能輸出)
對應的 fiber 實作程式碼如下:
請補完程式碼,使其運作符合預期。
作答區
KKK = ?
(a)
(char *) fiber_list[num_fibers].stack - FIBER_STACK
(b)
(char *) fiber_list[num_fibers].stack + FIBER_STACK
(c)
fiber_list[num_fibers].stack + 1
(d)
fiber_list[num_fibers].stack - 1
CCC = ?
(a)
fiber_list[i].pid != pid
(b)
fiber_list[i].pid == pid
(c)
fiber_list[i].pid != 0
(d)
fiber_list[i].pid == parent
延伸問題:
fibonacci
和 squares
這兩個函式的輸出字串可能會遇到無法一整行表示 (即 interleaving),請指出原因並修正