# 2019q1W7上: 陳奕熹 ## 測驗 `1` 請研讀原始程式碼和對應註解,補完 `find_next_bit` 函式的程式碼,確保符合 Linux 核心的 `find_next_bit` 語意並可通過 main 函式給定的測試。應用到 `bitops_ffs` 和確保新增的程式碼行數儘可能少。 ```cpp static inline size_t find_next_bit(const unsigned long *bitmap, size_t bits, size_t start) { unsigned long t; size_t l = BITS_TO_LONGS(bits); size_t first_long = start / BITS_PER_LONG; size_t long_lower = start - (start % BITS_PER_LONG); if (start >= bits) return bits; t = bitmap[first_long] & BITMAP_FIRST_WORD_MASK(start); for (size_t i = first_long + 1; !t && i < l; i++) { long_lower += BITS_PER_LONG; t = bitmap[i]; } if (!t) return bits; size_t pos; pos = long_lower + bitops_ffs(t) - 1; if (pos >= bits) return bits; return pos; } ``` 解題方向: 1. 第一個參考資料有一點點幫助,但更多的是我看不懂他中文在寫啥 最後還是看 source code 比較快 2. 其實參考 `find_next_zero_bit()` 實做可以大概知道整體思路 ```cpp size_t pos; unsigned long t; size_t l = BITS_TO_LONGS(bits); size_t first_long = start / BITS_PER_LONG; size_t long_lower = start - (start % BITS_PER_LONG); ``` 一開始的這部份把 bit-oriented 轉換成 long 表示(因為後面遞迴加的單位是 long),另外需要注意的是 `long_lower` 如同字面上意義,需要考慮到 start 並沒有與 long 做對齊的情況 ```cpp t = bitmap[first_long] | ~BITMAP_FIRST_WORD_MASK(start); t ^= ~0UL; ``` 這邊則是因為考慮到開頭可能不對齊的現象,特別弄了一個 BITMAP_FIRST_WORD_MASK 以取得 start 對齊後的位元 這邊的 t 只要不為零(全部的 bit 都是零),就是為找到答案 (`!t` 只要為 1 就代表根本沒有 bit set) `t ^= ~0UL;` 這一步是為了把 01 互換以取得 0 的位置 (跟 0xFFFFFFF 做「異或」其實就是求 1 補數) 但是在 `find_next_bit()` 因為已經是 1 就不需要額外做這個操作 其後只要注意到 `t ^= ~0UL;` 這步驟比較不同外,其他概念上是大致相同的 ## 測驗 `2` 承測驗 `1`,改寫 `main` 函式,強化測試的強度,允許檢驗隨機的 BITMAP test 組合 (也就是需要隨機變更 test 之位元內容) ```cpp int main(void) { srand(time(NULL)); for (int i = 1; i < MAX_TEST_BITS; i++) { bitmap_fill(test, i); for (int j = 0; j < 7; j++) { size_t rand_factor = (rand() % 0xff) + 1; test[j] ^= rand_factor; } assert(find_next_bit(test, i, 0) == 0); bitmap_zero(test, i); assert(find_next_bit(test, i, 0) == i); } return 0; } ``` 目前這個版本會卡在 assert ,因為隨機亂數還不能確定答案 當然也是可以假設只有固定一個 1 下排列組合,但是這樣測試的數值覆蓋率實在不好 同時如果可以的話修改 `bitmap_fill` 本身應該可以減少程式指令的運用 #### 2019/04/16 更新 根據之前看開源專案的經驗,像這類驗證 function correctess (包含函示庫間獨立正確的 reliance) 都會額外寫 test function 引用這些函示庫做測試 因此比較理想的測試方式,應該是寫一個 tester function 拿到 `find_next_bit` 的回傳與已知正確的實作方法比較輸出 ## 測驗 `3` 承測驗 `1`,用 C99 語法改寫 `bitops_ffs` 函式,使其不依賴 GNU extension,需要附上對應的測試程式碼。 ```cpp int my_ffsl(unsigned long x) { int n = 1; if ((x & 0x00000000FFFFFFFF) == 0) {n = n + 32; x >>= 32;} if ((x & 0x000000000000FFFF) == 0) {n = n + 16; x >>= 16;} if ((x & 0x00000000000000FF) == 0) {n = n + 8; x >>= 8;} if ((x & 0x000000000000000F) == 0) {n = n + 4; x >>= 4;} if ((x & 0x0000000000000003) == 0) {n = n + 2; x >>= 2;} return n - (int)(x & 1) + 1; } ``` 其實 ffsl 計算「從右數過來第一個 1 的位置」這個問題等價於 「計算 tailing zero 的數目(再加一)」 以上程式碼主要是根據 [Implementing GCC's Builtin Functions](https://blog.stephencleary.com/2010/10/implementing-gccs-builtin-functions.html) 改成 long 版本的
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.