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 = 00110011
0xAA = 10101010
0x55 = 01010101
x
分為兩半 , 左半邊的 bit 與右半邊互換 , 此時 x
被分為兩塊x
被分為四塊 0xCC = 11001100
0x33 = 00110011
x
被分為八塊 , 而各塊皆為 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
對應的位元設成 1res
hori_cnts[i]
: 用來記錄與點 i 在同一個水平線上的點數量vert_cnts[i]
: 用來記錄與點 i 在同一個鉛直線上的點數量dup_cnts[i]
: 用來記錄與點 i 重複的點數量slope_cnts[i]
: 用來記錄與點 i 在同個斜率 m 之線上的的點數量heads[i]
: 用來連結某個斜率下的所有點 point_node
static 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_cnts
ret
: 最少需要多少位元才可儲存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
拆為以下形式:
y
fls
: 找出某數最高位的 bit 1 , 最低為 0 最高為 63m = 1UL << (fls(x) & ~1UL)
: 題目平方根為向下取整 , 又 y
的平方最小一定為奇數個 bits , 因此當 x
最高位的 1 在偶數 bit 時( fls(x) 為奇數) , 要將 fls(x) 減一( fls(x) & ~1UL
) , 確保 y
平方小於等於 x
y
= 的過程 , 從 找到 , 其中 m 為 , y 為 (假設目前已找出 , x為尚未找出的bit) , 而 b = y + m
則為 為 1 時當前 會多出上一個 的值 , 當這個值大於 x
表示該 bit 應為 0 , 反之將 x
減去 b
, y
加上 m
m
為 , 要找下一個 bit 會右移兩位 , y
為 要找下一個 bit 會右移一位