contributed by < BooleanII
>
1
版本一使用 log2 操作,可獲得小於等於輸入值的 2 的冪次數值 a ,並以此數值進行 Digit-by-digit calculation 獲得平方根。
而 a 其實可以透過第 2 週測驗的測驗 3 ,使用 ffs (find first bit) 找尋 N 第一個 set (設定為 1) 的位元,而版本 2 即為以找到 ffs 的方式進行實作。
待確認問題
2
3
由於向左或向右位移一個位元等同於將該數值乘或除以 2 ,故 2 的冪次可以透過將 1 左移進行實現。因此,以 2 為底的對數的整數項,可以透過找到該數的 ffs 獲得,版本一的實作輸入數值進行右移直到找該數值的 ffs 後停止。版本一的實作對於輸入數值小於等於 0 時,則輸出 -1 進行例外處理。
版本二為加快運算速度,以二元搜尋 (binary search) 的方式找出 ffs ,當數值大等於 2 的 16 次冪 (0x10000) 時,可以直接一口氣像右位移 16 個位元;而當數值大於等於 2 的 8 次冪 (0x100)時,則可以一口氣向右位移 8 個位元。
__builtin_clz 為 gcc 內建函式,可回傳無號整數 (unsigned int) 中自 MSB 開始到第一個 1 的 0 個數,以 32 bit 系統為例,當輸入為 2 時輸出為 31 、輸入為 16 時輸出為 27 。透過使用此函式可獲得版本三的實作,將 31 減去 __builtin_clz 結果即可得到 ffs 的位置。
故測 3
答案如下:
3
延伸問題在 Linux 核心原始程式碼找出 log2 的相關程式碼 (或類似的形式),並解說應用案例
在 /usr/src 路徑下搜尋 log2 關鍵字獲得非常可觀的搜尋結果,為縮小範圍改以本次測驗的內容 ilog2 搜尋,並在結果中看到 hashtable.h 定義的 HASH_BITS 巨集 (macro) 有使用。
該巨集涉及到的 ARRAY_SIZE 巨集定義於 kernel.h 檔中:
__must_be_array 巨集定義於 compiler.h 檔中:
BUILD_BUG_ON_ZERO 巨集定義於 build_bug.h 檔中:
__same_type 巨集定義於 compiler_types.h 檔中:
__same_type 巨集使用 gcc 提供的 built-in 函式 __builtin_types_compatible_p 進行實作。 __builtin_types_compatible_p 用於比較兩個輸入參數的型態是否相同,相同則回傳 1 、不同則回傳 0 。需注意此巨集會忽略如 const 、 volatile 等 top level qualifier ,例如 int 與 const int 會被視為相同。
當 BUILD_BUG_ON_ZERO 巨集輸入為非 0 時,程式碼會因為於 struct (結構體)中宣告 -1 的 bit field ,而在編譯階段發生錯誤;反之輸入為 0 時則則因 bit field 長度為 0 而輸出 0 。透過上述機制使 __must_be_array 輸入為 pointer (指標)時,會在編譯時期就發生錯誤,避免後續獲得錯誤的陣列長度計算結果。
4
5
1
2
3