contributed by < ollieni >
版本一的程式是先對要找平方根的整數 N 取對數(以二為底),可以找出 msb (most significant bit) ,也就是用二進位表示這個整數時,最高位1是在從右開始數的第幾位。
有了 msb 後,因為整數 N 的平方根不可能超過 msb ,所以將 1 左移 msb 個位元後放入 a,接下來就可以開始用 while 迭代,在每一次迭代中,它會檢查 (result + a) * (result + a) 是否小於或等於 N。如果是,則將 result 加上 a,然後將 a 右移(除以二),迭代完就可以逼近整數平方根。
版本二就是不直接使用取對數的方法,用將 N 右移的方式,右移幾次 N 不大於 1,次數就是 msb,接下來就和版本一一樣了。
版本三
bit 的翻譯是「位元」,而非「位」,後者是量詞。
__builtin_clz(x)
函式返回 x
的二進制表示中從最高位到最低位第一個非零位前的零的個數。
這個版本用__builtin_clz(x)
函式找出 msb 。
((31 - __builtin_clz(x)) & ~1UL)
,用 31 減去 零的個數後 ,可以得到 msb , & ~1UL
把最後一位轉成 0 ,是因為每次 m 右移兩位,要強制對齊成偶數。
我覺得重點是 "mod 10 就是 tmp 減去 div 10 的結果乘 10"。
uint32_t x = (in | 1) - (in >> 2);
這行就等於,in最後一位強制為1 - (in/4),約等於 。
uint32_t q = (x >> 4) + x;
,這一行程式等同於。
接下來這幾行是為了讓 q 接近 ,加了四次 。
最後 *div = (q >> 3);
右移3位,等於除8,就變成。
而 *mod 就等於 in - ((q & ~0x7) + (*div << 1));
,in - 商數乘10。
版本一是將要取對數的樹一直右移,並計算右移的次數,以此找出 msb,要從 -1 開始加是因為 log1 = 0。
版本二則是檢查要取對數的值大於65535、256、16、2時,可以一次右移16、8、4、1個 bits。
版本三是使用測驗一有提到的 __builtin_clz(x)
找出最高位到最低位第一個非零位前的零的個數,並用 31 減去即可得到以二為底的對數。
閱讀權威材料。
根據題目
題目中的三元條件運算式就是這個數學式。
也就是說在 avg->internal
是 0 的情況下,avg->internel = (val << avg->factor)
。
對於為什麼要左移 factor bits,我問 Chatgpt後,有了以下的解釋 :
factor 是用於縮放內部值的因子。這個因子的作用是調整內部值的大小,以便在內部表示中容納指定範圍內的數值。
具體來說,factor 用於計算加權平均的內部表示,這涉及將實際值(例如計數或度量)轉換為內部表示。通常,為了在 EWMA 中處理大範圍的數值,需要將這些值進行縮放,以確保它們可以被有效地處理。因此,factor 就是用於進行這種縮放的參數。
而 avg->internal
不是 0 的情況下,(((avg->internal << avg->weight) - avg->internal) + (val << avg->factor)) >> avg->weight
,最後為什麼要右移 avg->weight 還不太明白。
前面的步驟都是和測驗三找對數時一樣的概念,重點在最後的回傳值,return (r | shift | x > 1) + 1;
將 shift 和 x > 1 (如果 x 大於1,則為1,否則為0) 添加到 r 中,並將結果加1返回。這是因為在一開始計算2的冪前,我們將 x 減1,所以最終結果需要再加1。
這段程式將 nums 裡的數,透過兩個 for 迴圈遍歷交叉使用__builtin_popcount(nums[i] ^ nums[j])
計算,(nums[i] ^ nums[j])
有幾個1,就可以得知在二進制時,每個位元的差。
最後右移 1 bits 的原因是因為會重複計算,比如 i = 1, j = 2 和 i = 2, j = 1 重複了,所以最後結果要除以2。
這題針對 static void __xt_remove(struct xt_node **root, struct xt_node *del)
這個函式作解釋。
首先,檢查待刪除節點 del 是否有右子節點(xt_right(del))。
如果有右子節點,找到右子樹中的最小節點 least,並將其設為待刪除節點 del 的右子節點。
如果 del 為根節點,則更新根節點為 least。
然後,使用 xt_update 更新根節點,以確保樹的平衡性。
如果待刪除節點 del 沒有右子節點,則檢查它是否有左子節點(xt_left(del))。
如果有左子節點,找到左子樹中的最大節點 most,並將其設為待刪除節點 del 的左子節點。
如果 del 為根節點,則更新根節點為 most。
然後,使用 xt_update 更新根節點,以確保樹的平衡性。