contribute by < Korin777 >
在 Linux 核心原始程式碼,include/linux/bitfield.h 提及一個巨集 GENMASK,其作用是依據給定的範圍,產生連續的 bitmask,例如:
GENMASK(6, 4) 產生 GENMASK(39, 21) 產生 0x000000ffffe00000 (64 位元)unsigned long 為 8 位元組寬度 (符合 LP64 資料模型),以下是可能的 GENMASK 巨集的定義:~0UL 每個位元皆為 1,而 GENMASK 則會將 h ~ l 以外的位元都變為 0~0UL 的 63 ~ h 位元(不包括 h)變為 0 => (~0UL) >> (63 - h)~0UL 的 l ~ 0 位元(不包括 l)變為 0 => (~0UL) >> (l) << (l)((~0UL) >> (63 - h)) & ((~0UL) >> (l) << (l))~3 二進位表示中 , 第 0 及第 1 個 bit 為 0 其餘皆為 1 , 因此 v & ~3 能夠確保地址為 4 的倍數且比 v 小0xCC = 11001100 0x33 = 001100110xAA = 10101010 0x55 = 01010101x 分為兩半 , 左半邊的 bit 與右半邊互換 , 此時 x 被分為兩塊x 被分為四塊 0xCC = 11001100 0x33 = 00110011x 被分為八塊 , 而各塊皆為 1 bit , 反轉完成foreach_int 即 foreach_ptr 為 Variadic Macros 可以傳入可變數量的參數(即 ... 可為零或多個) , 而在最後被命名的 argument(即 i) 後的所有 argument(包含他們之間的逗號) 會被前處理器展開到有 __VA_ARGS__ 的地方(((int[]){__VA_ARGS__})[0]) 即展開為 (((int[]){0, -1, 100, 0, -99})[0]) 也就是 array ((int[]){0, -1, 100, 0, -99}) index 0 的值_foreach_i 會被 assign 成 (((i) = ((int[]){__VA_ARGS__})[0]), 0) 括號中最後的那個值 , 也就是 0i 就要改為 array 下一個 index 的值 , 因此 _foreach_i 要先加 1(即 ++_foreach_i)dividend 除以 divisor 的商之二進位表示中 bit 為 1 的位元 , 並將 res 對應的位元設成 1reshori_cnts[i] : 用來記錄與點 i 在同一個水平線上的點數量vert_cnts[i] : 用來記錄與點 i 在同一個鉛直線上的點數量dup_cnts[i] : 用來記錄與點 i 重複的點數量slope_cnts[i] : 用來記錄與點 i 在同個斜率 m 之線上的的點數量heads[i] : 用來連結某個斜率下的所有點 point_nodestatic bool can_insert(struct list_head *head, int p1, int p2) : 用來判斷一個點該不該被加到 list_head[i]
list_head[i] 一開始都可以插入點list_head[i] 後 , 除非 p1 為第一個插入的點 , 否則就不允許插入 , 這是因為 maxPoints 會先將 points[1~pointsSize-1] 中與 points[0] 斜率為 m 的點加入對應的 list_head[i] , 再來換看 points[1] , 而 points[1] 與 points[2~pointsSize-1] 一樣有斜率為 m 的點且對應到同一個 list_head[i] , 這時要是允許插入 , 就會出現點重複的情況hori_cnts、vert_cnts、slope_cnts , 當中最大的即為 Max Points on a Lineint hash = dx * dy - 1333 * (dx + dy) 應改為 int hash = dx * dy - 1333 * (dx - dy); , 否則 (0,0)、(3,4)、(4,3) 會被判斷再同意條線上 , 因 (0,0)、(3,4) 及 (0,0)、(4,3) hash 值相同dup_cntsret : 最少需要多少位元才可儲存v 尚未檢查的 bits 分為兩半 , 並看左半邊是否有值v , 這時右半邊查看完畢 ; 沒有則表示最高位元的 1 在右半邊 , 這時左半邊查看完畢 , 重複步驟 1 直到剩兩個尚未檢查的 bitret = v > 0; 及 ret += v > 1; 被檢查到p 為 pointer to pointer 所以應該 assign 成 pointer 的地址 e.g:&(*p)->left考慮以下進行記憶體地址對齊 (alignment) 的巨集:
(((x) + MAX_ALIGNMENT - 1) 確保新的記憶體位置大於等於原本的記憶體位置 , 達成向上對齊& ~(MAX_ALIGNMENT - 1) 將低位的 4 個 bit 清為 0 , 確保記憶體位置為 16 的倍數撰寫出對應 ROUND_DOWN 巨集:
x 低位的 4 個 bit 清為 0 就能確保記憶體位置為 16 的倍數 , 且新的記憶體位置也小於等於原記憶體位置 , 達成向下對齊x 除以 divisor 四捨五入後的結果(__d >> 1) 相當於讓 (__x)/(__d) 四捨五入 , 當 (__x) >= 0.5*(__d) 則 (__d)-(__x)%(__d) <= (__d >> 1) => 進位 , 又整數除法會無條件捨去小數(((__x) > 0) == ((__d) > 0))) 判斷結果為正或負 , 負數捨去小數點相當於取大的數 , 因此要改成減 ((__d) >> 1)(((typeof(x)) -1) > 0 || ((typeof(divisor)) -1) > 0 判斷 x 或 divisor 是否為無號數 , 若有無號數 , 因另一數也會被轉型成無號數 , 所以結果必為正數x 拆為以下形式:
yfls : 找出某數最高位的 bit 1 , 最低為 0 最高為 63m = 1UL << (fls(x) & ~1UL) : 題目平方根為向下取整 , 又 y 的平方最小一定為奇數個 bits , 因此當 x 最高位的 1 在偶數 bit 時( fls(x) 為奇數) , 要將 fls(x) 減一( fls(x) & ~1UL) , 確保 y 平方小於等於 xy = 的過程 , 從 找到 , 其中 m 為 , y 為 (假設目前已找出 , x為尚未找出的bit) , 而 b = y + m 則為 為 1 時當前 會多出上一個 的值 , 當這個值大於 x 表示該 bit 應為 0 , 反之將 x 減去 b , y 加上 mm 為 , 要找下一個 bit 會右移兩位 , y 為 要找下一個 bit 會右移一位