linux2022
目的: 檢驗學員對 數值系統, linked list, bitwise 的認知
作答表單: 測驗 1-4 (Linux 核心設計)
作答表單: 測驗 5-7 (Linux 核心實作)
1
考慮以下對二個無號整數取平均值的程式碼:
這個直覺的解法會有 overflow 的問題,若我們已知 a, b 數值的大小,可用下方程式避免 overflow:
接著我們可改寫為以下等價的實作:
其中 EXP1
為 a
, b
, 1
(數字) 進行某種特別 bitwise 操作,限定用 OR, AND, XOR 這三個運算子。書寫規範:
a | b ^ 1
EXP1
必定包含 a
, b
, 及 1
(數字) 等字元a
再寫 b
(
和 )
我們再次改寫為以下等價的實作:
其中 EXP2
和 EXP3
為 a 和 b 進行某種特別 bitwise 操作,限定用 OR, AND, XOR 這三個運算子。書寫規範:
a | b
EXP2
和 EXP3
必定包含 a
和 b
字元a
再寫 b
(
和 )
作答區
EXP1
= ?
EXP2
= ?
EXP3
= ?
延伸問題:
移動平均(Moving average),又稱滾動平均值、滑動平均,在統計學中是種藉由建立整個資料集合中不同子集的一系列平均數,來分析資料點的計算方法。
移動平均通常與時間序列資料一起使用,以消除短期波動,突出長期趨勢或周期。短期和長期之間的閾值取決於應用,移動平均的參數將相應地設置。例如,它通常用於對財務數據進行技術分析,如股票價格、收益率或交易量。它也用於經濟學中研究國內生產總值、就業或其他宏觀經濟時間序列。
2
改寫〈解讀計算機編碼〉一文的「不需要分支的設計」一節提供的程式碼 min
,我們得到以下實作 (max
):
其中 EXP4
為 a
和 b
進行某種特別 bitwise 操作,限定用 OR, AND, XOR 這三個運算子。書寫規範:
a | b ^ 1
EXP4
必定包含 a
和 b
字元a
再寫 b
(
和 )
EXP5
為 a
和 b
的比較操作,亦即 logical operator,限定用 >
, <
, ==
, >=
, <=
, !=
這 6 個運算子。書寫規範:
a > b
EXP5
必定包含 a
和 b
字元a
再寫 b
(
和 )
延伸閱讀:
作答區
EXP4
= ?
EXP5
= ?
延伸問題:
git log
檢索。3
考慮以下 64 位元 GCD (greatest common divisor, 最大公因數) 求值函式:
註: GCD 演算法
改寫為以下等價實作:
請補完程式碼。書寫規範:
u | v
(
和 )
作答區
COND
= ?
RET
= ?
延伸問題:
__builtin_ctz
改寫 GCD,分析對效能的提升;4
在影像處理中,bit array (也稱 bitset
) 廣泛使用,考慮以下程式碼:
考慮 GNU extension 的 __builtin_ctzll
的行為是回傳由低位往高位遇上連續多少個 0
才碰到 1
。
範例: 當
a = 16
16
這個十進位數值的二進位表示法為 00000000 00000000 00000000 00010000
從低位元 (即右側) 往高位元,我們可發現 ,於是 ctz 就為 4,表示最低位元往高位元有 4 個0
用以改寫的程式碼如下:
其中第 9 行的作用是找出目前最低位元的 1
,並紀錄到 t
變數。舉例來說,若目前 bitset
為 ,那 t
就會變成 ,接著就可以透過 XOR 把該位的 1
清掉,其他保留 (此為 XOR 的特性)。
若 bitmap 越鬆散 (即 1
越少),於是 improved
的效益就更高。
請補完程式碼。書寫規範:
bitset | 0x1
-bitwise
的特性(
和 )
作答區
EXP6
= ?
延伸問題:
5
以下是 LeetCode 166. Fraction to Recurring Decimal 的可能實作:
請補完,使得程式碼符合預期,儘量以最簡短且符合一致排版的形式來撰寫。
作答區
PPP
= ? (表示式)
MMM
= ? (List API 函式)
EEE
= ? (表示式)
延伸問題:
例如,判斷負號只要寫作
bool isNegative = numerator < 0 ^ denominator < 0;
搭配研讀 The simple math behind decimal-binary conversion algorithms
mm/
目錄 (即記憶體管理) 中,找到特定整數比值 (即 fraction) 和 bitwise 操作的程式碼案例,予以探討和解說其應用場景6
__alignof__
是 GNU extension,以下是其可能的實作方式:
請補完上述程式碼,使得功能與 __alignof__
等價。
請補完,使得程式碼符合預期,儘量以最簡短且符合一致排版的形式來撰寫。
作答區
M = ?
X = ?
延伸問題:
__alignof__
的使用案例 2 則,並針對其場景進行解說ALIGN
, ALIGN_DOWN
, ALIGN_UP
等巨集,探討其實作機制和用途,並舉例探討 (可和上述第二點的案例重複)。思索能否對 Linux 核心提交貢獻,儘量共用相同的巨集7
考慮貌似簡單卻蘊含實作深度的 FizzBuzz 題目:
直覺的實作程式碼如下: (naive.c
)
觀察 printf
的(格式)字串,可分類為以下三種:
"%d"
: 長度為 2 B考慮下方程式碼:
我們若能精準從給定輸入 i
的規律去控制 start
及 length
,即可符合 FizzBuzz 題意:
以下是利用 bitwise 和上述技巧實作的 FizzBuzz 程式碼: (bitwise.c
)
其中 is_divisible
函式技巧來自 Faster remainders when the divisor is a constant: beating compilers and libdivide,甚至 gcc-9 還內建了 FizzBuzz optimization (Bug 82853 - Optimize x % 3 == 0 without modulo)。
請補完,使得程式碼符合預期,儘量以最簡短且符合一致排版的形式來撰寫。
對於處理器來說,每個運算所花的成本是不同的,比如 add
, sub
就低於 mul
,而這些運算的 cost 又低於 div
。依據〈Infographics: Operation Costs in CPU Clock Cycles〉,可發現整數除法的成本幾乎是整數加法的 50 倍。
所以如何處理 div
運算是每個編譯器最佳化都關注的議題。考慮 , 是一個 constant,除式可以表示成 ,若 是 2 的冪,可以將除法轉換成乘法跟位移,cost 會比 div
少很多,如果除數 不是 2 的冪,則 需要做一些特別的處理,在若干微處理器架構中,若 足夠大,其實 可事先預估。
文章中還有介紹一些其他的除法如下:
作答區
KK1
= ? (變數名稱)
KK2
= ? (變數名稱)
KK3
= ? (表示式,不包含小括號)
延伸問題:
naive.c
和 bitwise.c
效能落差
printf
更換為 sprintf
bitwise.c
程式碼,試圖運用更少的指令來實作出 branchless;
kernel/time/
目錄的標頭檔和程式碼)
過程中,你可能會發現可貢獻到 Linux 核心的空間,請充分討論