contributed by < jim12312321
>
解析:
這題跟 第三周測驗題第 7 題想法上大致一致,一樣是用 binary search,每次對半檢查,檢查當前 bits 中的上半部分是否有值,之後再位移 x
並將結果相加得到答案。
不要加上「的概念」,本質上就是 binary search!
jservImage Not Showing Possible ReasonsLearn More →
- The image file may be corrupted
- The server hosting the image is unavailable
- The image path is incorrect
- The image format is not supported
本題在第 14 行時檢查到 0x3
,也就是剩最後兩個 bits ,經過位移後就回傳答案了,因此我們可知題目將以下步驟濃縮在 (EXP1)+1
中。
其中第三行中的 shift
可以直接用 (x > 1)
取代,因此目前可以簡化成
而又因為現在的 x
只剩 2 個 bits ,因此判斷是否大於 1 等價於右移 1 ,程式碼可以進一步簡化
EXP1
r | shift | x >> 1
改進程式碼,使其得以處理 x = 0 的狀況,並仍是 branchless
主要想法就是針對輸入 0 這個特例進行處理。
一開始的 x--
會使值從 0 變為 0xFFFFFFFF ,之後每次位移後都將值補回去讓其隨時都為 0xFFFFFFFF ,最後 0xFFFFFFFF +1 就會等於 0。
思考如何藉由巨集來簡化程式碼,注意 bitmask/generator 的設計
解析:
這題一樣是利用 binary search ,每次對半檢查 x
中的下半部 (e.g. 假設現在 x
為 16 bits ,那下半部就是第 0 到 7 個 bits) 是否有值,若有值則表示應該繼續找下去,若沒有值則表示 first set bit 在目前的上半部,因此要將當前字串右移並累加結果。
EXP2
x & t
EXP3
o += shift
迴避 while, for, goto 等關鍵字以改寫出功能等價的實作
naïve 版本:
因為本質上是 binary search ,而對於 unsigned long (64 bits in LP64) 中最多就是重複 6 次,直接展開即可。
遞迴版本:
除了比較簡短之外,對應不同型態的數值也不用重新思考要對切幾次,可以直接修改 BITS_PER_LONG
, t
, x
的資料型態即可,另外要特別注意,因為希望在遞迴執行時 shift
, t
, o
不用特別傳入且始終為同一個,因此變數宣告時要加上 static
修飾詞。
暫時想不到更精簡的寫法了。
在 Linux 核心原始程式碼的 include/asm-generic/bitops 目錄找出相關程式碼,並探討應用案例
在 include/asm-generic/bitops 中可以看到許多相關實現方法,如: __ffs, __fls, ffs, fls 等方法。
我們來追蹤 __ffs 的應用情境,可以在 drivers/clk/ti/clkt_dpll.c 中的 _omap2_dpll_is_in_bypass
找到他。
就像註解所說的,在這裡 __ffs
的目的就是為了從 mask 的高位 set bit 逐步走訪所有 set bit (而 mask ^= (1 << val);
就是為了消除找到的 first set bit) 並且判斷是否為 bypass mode 。
解析︰
這題只是單純考驗指標的指標運用技巧,在 comsumer_del
中需要走訪 foo->comsumers
找到指定移除的結點 fc
。
所以我們知道在 EXP4
中需要讓 con
繼續走訪 linked list 並在 EXP5
時移除找到的結點。
EXP4
con = &(*con)->next
EXP5
fc->next
另外在延伸問題 1 中也要求以下問題
區分
foo
和foo_consumer
的好處
我認為這樣的用意主要是為了封裝,模組化比起大雜燴來得好維護,另一個好處則是增加程式易讀性,方便理解和維護。
在 task_switch
和 task_join
中都需要將當前的 task 從 task list 中移除。
EXP6
list_del(&t->list)
EXP7
list_del(&t->list)
在 task0
或 task1
中執行完 task_add
後需要返回到 schedule
中。
EXP8
longjmp(sched, 1)
EXP9
longjmp(sched, 1)
union 有別於 struct 的特點在於 union 所佔的記憶體空間大小以 union 中占最大空間的成員,因此 DECL0
需要選擇所占空間最小的型態。
DECL0
char __c[1]