contributed by < padaray
>
1
版本一:
對輸入的參數 N
以 2 為底數取 log,意義是當我們將 N
取 log2 時,可以得到 most significant bit (msb)。
對 1 左移 msb 個位元後存入變數 a
,意義是找出一個必定大於 N
的平方根的數,利用此數來逼近找到 N
的平方根。
最後使用 while 迴圈,計算 a + result
的平方是否大於 N
,若小於 N
則將此數存入 result
變數,對 a
右移 1 bit,繼續計算,直到 a
= 0。
版本二:
版本二的差別是不使用 math.h
的 log2
函式,直接對參數 N
進行右移,右移至參數為 0 時,則代表找到 most significant bit。此方法將程式的可移植性增強,並且不影響原本的函式原型 (prototype) 和精度 (precision)
版本三:
完整程式碼(無遮蔽處)
__builtin_clz(x)
:是 gcc 內建處理二進位的其中一個函式巨集,此函式會回傳 counting leading zero,幫助我們找到 most significant bit。
在 for 迴圈中左移 31 - __builtin_clz(x)
bit 數得到 msb,& ~1UL
可以確保最後一個 bit 為 0,理由是變數 m
必須是偶數對應到 。而 m 右移兩個 bit 是對應到
2
除法原理:
程式碼如下:
如果我們想要使用 bitwise operation 來實作除法,如果被除數包含了除了 2 以外的因數,就會造成結果不精確,所以使用以下方式。
假設除數為 10,我們必須找到 ,最後發現是
程式碼如下:
(((tmp >> 3) + (tmp >> 1) + tmp) << 3)
使用 bitwise operation 取得一個分子有 13 的分數,因此用 ,之後再左移三位消掉分母 8。
d0
、d1
、d2
是為了將 tmp
右移時損失的 bit 數加回,加回後再右移 7 位也就是除以 128 得到商數。
(((q << 2) + q) << 1)
相當於 ,也就是最一開始程式碼的 carry * 10
。
最終程式碼可包裝為以下:
3
版本一:
初始化變數 log
為負一,直接對參數 i
進行右移,每次右移將 log++
,右移至參數 i
為 0 時
版本二:
完整程式碼(無遮蔽處)
為了避免數字過大每次位移一個 bit 太慢,例如:65536 需要位移 16 個 bit,因此加入條件判斷,若大於特定 2 的冪次方,直接移動該次方的位元數。
版本三:
4
Exponentially Weighted Moving Average (EWMA) 是一種統計方法,透過對每筆資料給予不同的權重計算平均,通常越新的資料權重就越高,越舊的資料權重越小,好處是可以適應新的資料變化,又保留一定的歷史資料影響。
數學定義:
: 舊資料加權降低的程度,越高代表降低越快。介於 0 ~ 1 之間
: 時間 t 時的資料
: 時間 t 時算出的 EWMA
以下為程式碼實作:
internal
代表目前計算的 ewma (數學式中的 ) , (avg->internal << avg->weight)
代表數學式中的 (但不知道原因為何),因此 。
當 internal
為 0 時,internal
代入 (val << avg->factor)
寫成公式為 。
當 internal
不為 0 時,internal
代入 (((avg->internal << avg->weight) - avg->internal) + (val << avg->factor)) >> avg->weight
寫成公式為 ,轉換一下可以得到
5
3
使用下方程式碼計算 第五、六行判斷參數 x
是否大於 0xFFFF,意義是確定 x
的 msb 是否位於高位的 16 bit,若為真,將 x
右移 16 bit。
第七、八、九行判斷參數 x
在這剩下的 16 bit 中,msb 是否位於高位的 8 bit,若為真,將 x
右移 8 bit,將右移的位數紀錄在 r
中。
第十行到第十四行依此類推。
第四、十五行將 x
先 -1 後 + 1 回傳是為了處理 2 的冪次方,若不處理會讓 2 的冪次方多計算一次,例: 經過無條件進位法,會變成 8,因此要先減 1
1