contributed by < Wufangni
>
i_sqrt
為找出平方根的函式,下面為版本一的作法:
使用 log2
找出最高位元數 msb
,接著利用 if ((result + a) * (result + a) <= N)
判別本次迴圈的結果取平方是否小於原數,若不是則持續往下找,直到找出平方可小於原數的結果即為他的平方根。
版本二使用迴圈方式替代 log2
函式找出最高位元 msb
:
因 mod
的計算量較大,根據除法原理利用已計算出來的 tmp / 10
可將 %
改寫成下面形式:
接著著手改寫 divmod_10
方法:
(in | 1) - (in >> 2)
可看成 ,化簡開可得 ,因此 q
的計算結果為 , 再整理後可得 ,做了四次 q = (q >> 8) + x;
讓 q
的結果更趨近於 , 最後可計算 div
結果,。
mod
計算則利用 (q & ~0x7)
方式,將 ~0x7
看待成 0x11...1000
與 q
做 &
計算,相等於 div
乘上 ,再與 (*div << 1)
相加可得結果為 ,根據上述提到的 mod
簡化算法 tmp = tmp - carry * 10
代入數值,mod
即為 結果。
定義一個 ilog2
用來找出以 2 為底的對數,每次迴圈中 i 的二進位值都會右移一格,用 log
作為計數器計算有幾個 。
上述方法因每個 bit
都需掃過一次做計算,因此改良成下面版本,在迴圈中新增判別式判斷 i 是否大於某個 ,若達成條件則一次移動 n 格 bit
,以減少總迴圈次數。
使用 GNU 中提供的 __builtin_clz
,因輸入不能為零所以設置 v | 1
作為輸入。
預先定義 ewma
結構, internal
為當前 ewma
的值, factor
為縮放因子,weight
用來決定衰減的 大小。
初始化 ewma
結構體,因 factor
及 weight
必須為 2 的冪,使用 is_power_of_2
排除可能報錯的值,接著使用測驗 3 提及的 ilog2
取出 2 的次方。
創建 *ewma_add
更新 ewma
,添加新資料 val
,若 avg->internal
為空值代表 val
為 ,直接填入 val << avg->factor
,其餘情況則按照 更新 。
以 表示, 則可以以 (val << avg->factor)) >> avg->weight
實現。
可寫成 ,乘回 avg->internal
展開可得 ,前半部分可以 ((avg->internal << avg->weight) - avg->internal)
實現,最後因 (val << avg->factor)) >> avg->weight
也需 >> avg->weight
因此將此移至算式尾端當分母。
計算數值的二進位表示法中有被設置的 bit
數量, popcount_naive
為其中一種方式:
利用 v &= (v - 1)
重置數值中 LSB
位元,並使用 n = -(~n)
方式對 n
加一,直到所有 LSB
位元重置為止。
以另一種方式做改寫:
以 32bit 舉例,population count 可以下列數學式表示:
為了避免每個 bit 都做一次計算,可以以每 4 個 bit 同時做計算,即:
n = (v >> 1) & 0x77777777
得出,持續累加三次得到以 4 bits 為單位的 set bit
數量。
利用一次位移一個 4 bits 單位做相加乘上 0x0F0F0F0F
過濾多餘的內容,可得以下數列, 為第 n 個單位 set bit
數量。
最後乘上 0x01010101
並取出在原 A6 位置的結果 (B7+B6+B5+B4+B3+B2+B1+B0),即為總 set bit
數目。
Hamming distance 為兩數列不相同位元之數目,透過 GCC 內建函式庫中提供 __builtin_popcount(x)
可計算 set bit
數量,可利用 特性(相同為0,不同為1)計算 ,得出數列 A 與數列 B 相異位元的數列,即為 A ^ B
。
從 xtree.h
中先觀察 xt_node
結構:
*parent
作為指向父節點的指標,*left
及 *right
分別指向左右子樹的根節點,hint
則作為判斷是否處於平衡的變數。
利用 treeint_xt.c
中提供對 xt_tree
的基本操作,完成 __xt_remove
及 xt_insert
等節點操作。