sysprog2020
目的: 檢驗學員對 C 語言指標, 數值系統 及 bitwise 操作 的認知
1
LeetCode 461. Hamming Distance 提及,兩個整數間的 Hamming distance 為其二進位的每個位元的差。請計算輸入參數兩整數 x 與 y 的 Hamming distance,例如整數 1
的二進位為 0 0 0 1
,而整數 4
的二進位為 0 1 0 0
,則 1
與 4
的 Hamming distance 為 2
。
上圖 hypercube (中文翻譯:超方形) 中,紅色路徑的 0100
到 1001
的 Hamming distance 為 3
,而藍色路徑的 0110
到 1110
的 Hamming distance 則是 1
。
運用第 3 周測驗 提到的 __builtin_popcount
(gcc extension 之一),我們可實作如下:
請補完程式碼。
參考資訊:
作答區
OP = ?
(a)
|
(b)
&
(c)
^
(d)
+
(e)
-
延伸問題:
2
LeetCode 1483. Kth Ancestor of a Tree Node 大意:
給你一棵樹,樹上有 n 個節點,編號自 0 到 。樹以父節點陣列的形式提供,其中
parent[i]
是節點 i 的父節點。樹的根節點是編號為 0 的節點。請設計treeAncestorGetKthAncestor(TreeAncestor *obj, int node, int k)
函式,回傳節點 node 的第 k 個祖先節點。若不存在這樣的祖先節點,回傳-1
。樹節點的第 k 個祖先節點是從該節點到根節點路徑上的第 k 個節點
Input:
7
表示共有 7 個節點GetKthAncestor(3, 1)
預期回傳 1
,後者是 3
的父節點,即「上 1
代」;GetKthAncestor(5, 2)
預期回傳 0
,後者是 5
的祖父節點,即「上 2
代」;GetKthAncestor(6, 3)
預期回傳 -1
,因為不存在這樣的節點Output:
以下是參考 C 程式實作:
請補完。
作答區
AAA = ?
(a)
int ***parent
(b)
int **parent
(c)
int *parent
BBB = ?
(a)
(-2)
(b)
(-1)
(c)
0
(d)
1
(e)
2
CCC = ?
(a)
1
(b)
i
(c)
i >> 1
(d)
i >> k
(e)
k << i
(f)
1 << i
延伸問題:
treeAncestorCreate
函式內部,若干記憶體被浪費,請撰寫完整測試程式碼,並透過工具分析;3
白板 coding 其實本意 (最好不要是) 不是考一些你已經會的東西,而是考一個你可能不會的問題,然後你要 keep trying, keep doing 下去,因為它的本質是在考一個未來你可能碰到的問題 (而且可能 Google 不到)。
考慮貌似簡單卻蘊含實作深度的 FizzBuzz 題目:
直覺的實作程式碼如下: (naive.c
)
觀察 printf
的(格式)字串,可分類為以下三種:
"%d"
: 長度為 2 B考慮下方程式碼:
我們若能精準從給定輸入 i
的規律去控制 start
及 length
,即可符合 FizzBuzz 題意:
以下是利用 bitwise 和上述技巧實作的 FizzBuzz 程式碼: (bitwise.c
)
gcc-9 還內建了 FizzBuzz optimization (Bug 82853 - Optimize x % 3 == 0 without modulo)。
請補完。
作答區
KK1 = ?
(a)
div5(b)
div3(c)
2(d)
1KK2 = ?
(a)
0(b)
1(c)
2(d)
div3(e)
div5KK3 = ?
(a)
0(b)
1(c)
2(d)
div3(e)
div5延伸問題:
naive.c
和 bitwise.c
效能落差
printf
更換為 sprintf
bitwise.c
程式碼,試圖運用更少的指令來實作出 branchless;
4
考慮到整數 PAGE_QUEUES
可能有以下數值:
給定 size_t offset
,試著將原本運算:
由於 PAGE_QUEUES
的數值分佈已知,在整數除法時,可思考加速運算的機制。需要注意,某些硬體平台缺乏整數除法指令 (如 Arm Cortex-A8),即使 Intel 公司出品的 Core 處裡器 Sandy Bridge 微架構中,針對 64 位元整數的除法運算,會佔用 40 到 103 個處理器週期,運算成本仍屬沈重。
來源: Agner Fog’s instruction tables,第 180 頁
於是我們可預先進行計算,從而避免整數除法指令的使用: (假設在 x86_64 硬體執行 GNU/Linux 並透過 gcc/clang 編譯)
其中 CASES
可能形如:
這樣的組合,請用最少的 case-break 敘述做出同等 size_t blockidx = offset / PAGE_QUEUES;
效果的程式碼。
參考資料:
Built-in Function:
int __builtin_ffs (int x)
Returns one plus the index of the least significant 1-bit of x, or if x is zero, returns zero.
作答區
CASES
至少該包含哪些數字: (複選)
(a)
2(b)
3(c)
4(d)
5(e)
6(f)
7(g)
8(i)
9(j)
10延伸問題:
__builtin_ffs
,大幅降低記憶體開銷;