linux kernel internal 2022 quiz2
1
主要思路為 a / 2
+ b / 2
,但是這裡並沒有考慮兩奇數需要進位的問題。若兩者都是奇數,如 a = 3, b = 5
,依照原本的運算方法,會產生 1 + 2 = 3
,但是與答案 4
仍有落差。因此 EXP1
需要填入兩者皆是奇數的判斷式,故 EXP1 = a & b & 1
,若兩者皆為奇數,則進位
由你所不知道的C語言:數值系統篇可知此題解答
如果沒有看過數值系統篇的話,主要思路須從 >> 1
著手。我們可以知道加法是由一個carry
及一個sum
組成,>> 1
代表除以2
。因此,我們可以先做一個加法器如下:
其中,sum = a ^ b
,carry = a & b
,上面的過程亦可使用遞迴實做。
由此可知,若 (a + b)
其實是可以寫成 sum + carry << 2
,此時所求為 (a + b) / 2
也就可以寫為 (sum + carry << 2) >> 2
此時將此式展開為 sum >> 2 + carry
此時將sum
與carry
帶入得到(a ^ b) >> 2 + (a & b)
,即為所求
加法程式碼,遞迴:
比較三種加法,這邊開啟O3
優化,比較其組合語言
原始程式碼
對應組合語言:
由組合語言我們可以發現,除以 2 在組合語言是 >> 2
,比較讓人意外的是,avg_0
使用最少指令,原本會以為利用 bitwise operator
轉譯成指令的數量最少,由此可以得到加法的成本還是比位元操作的成本還要低
研讀 Linux 核心原始程式碼 include/linux/average.h
EWMA
BUILD_BUG_ON
linux/build_bug.h
得
If you have some code which relies on certain constants being equal, or some other compile-time-evaluated condition, you should use BUILD_BUG_ON to detect if someone changes it.
__builtin_constant_p
BUILD_BUG_ON_NOT_POWER_OF_2
READ_ONCE
ilog2
問題:
移動平均(Moving average),又稱滾動平均值、滑動平均,在統計學中是種藉由建立整個資料集合中不同子集的一系列平均數,來分析資料點的計算方法。移動平均通常與時間序列資料一起使用,以消除短期波動,突出長期趨勢或周期。短期和長期之間的閾值取決於應用,移動平均的參數將相應地設置。例如,它通常用於對財務數據進行技術分析,如股票價格、收益率或交易量。它也用於經濟學中研究國內生產總值、就業或其他宏觀經濟時間序列。
2
Reference: Bitwise Max
改寫〈解讀計算機編碼〉一文的「不需要分支的設計」一節提供的程式碼 min,我們得到以下實作 (max):
問題:
主要解題思路為
由互斥或 (exclusive or, xor) 的性質得到:
此時由提示可知 EXP4
為 bitwise operator
,可以推斷出 EXP4 = a ^ b
,由提示可知 EXP5
屬於 >
, <
, ==
, >=
, <=
, !=
中的其中一個,可以推得 EXP5 = a < b
3
問題
輾轉相除法如下所示,以 72, 48 為例:
由上可知,最大公因數為 24,以相同的例子帶入上方程式碼:
shift
為右移次數,右移三次時,兩者有其一為奇數: u = 9, v = 6
進入迴圈後:
可以推得 RET = u << shift
, COND = v
利用 __builtin_ctz
改寫 GCD
,由 GCC 6.59 Other Built-in Functions Provided by GCC 找到 __builtin_ctz
含式的意義
Returns the number of trailing 0-bits in x, starting at the least significant bit position. If x is 0, the result is undefined.
由 kernel __ffs 中找到巨集的意義
__ffs — find first set bit in word
效能分析:
測試程式碼:
4
問題:
5
Reference: Leetcode 166
問題:
例如,判斷負號只要寫作
bool isNegative = numerator < 0 ^ denominator < 0;
搭配研讀 The simple math behind decimal-binary conversion algorithms
6
解題思路:
由 __alignof__
可知
遇到上面的問題先上我們抽絲剝繭,一步一步分析,這邊模仿頭腦體操進行解析:
利用 linux command: grep -rn alignof
搜尋 alignof
,尋找結果多的驚人,以下僅節錄部分結果:
ALIGN
, ALIGN_DOWN
, ALIGN_UP
… 在 include/linux/align.h
。然而,在這個標頭檔中的 ALIGN
與本題的作法不同,與 quiz3
的題目相近
問題:
7
Reference: Leetcode 412
問題:
naive.c
和 bitwise.c
效能落差stream I/O
帶來的影響,可將 printf
更換為 sprintf
過程中,你可能會發現可貢獻到 Linux 核心的空間,請充分討論
首先需要了解本題的 mod
怎麼實做,以下面為例:
與一般的取餘數不同,本題實做採用溢位 (overflow) 的方式,若為 3 的倍數,以 3 為例, n * M = 0xFFFFFFFFFFFFFFFF + 3 = 2
;若不是 3 的倍數,以 2 為例,則 n * M = 0xAAAAAAAAAAAAAAAC > 0x5555555555555555