contributed by < yeh-sudo
>
1
假設要求的平方根為 ,並且將 表示為以下形式:
其中 為 bit pattern , 為最高位的 1 。所以 可以寫成:
設 , 可以表示成:
根據 Digit-by-digit calculation :
設 ,則 可以表示為:
而 即為要求出的平方根。所以,從 一路試到 ,測試 是否成立,分為兩種情況:
在檢驗時,如果每次都要計算 ,會需要很高的成本,所以可以利用重複利用每一次計算的差值 ,可以得出:
設 ,則可以寫成以下遞迴關係:
將 拆成 與 兩部份,
可以從 與 推出下一輪的 與 ,再用 與 推出 與 ,直到推出 即為所求的平方根 ,而首項 。
此處的 成立的條件為 ,若不成立,則 ,所以當 時, ,反之則 。所以最後可以將 寫成以下關係:
在程式碼中, 對應到變數 z
, 對應到變數 m
, 差值 對應到變數 x
。由於是紀錄差值,所以每當差值大於等於 ,也就是 b = z + m
時,就將差值扣掉 b
,並且,因為差值為正,代表 ,也就是 ,所以 ,對應到的程式碼操作為 z += m
,持續進行迴圈直到 m
為 0 時,結束迴圈。
程式碼 (31 - __builtin_clz(x))
的作用是找到最大的 bit 所在的位置,而使用第二週測驗題提供的 __ffs
,可以實作出找出對大 bit 的 fls
函式,實作方法是當 x
不為 0 時,持續尋找 ffs
,找到時就使用測驗題提供的 __clear_bit
將找到的 bit 清為 0 ,當 x
為 0 時,代表最後找到的 ffs
為最大的 bit 。
另外還有一個方法可以找出 fls
,將 x
的逐位元反轉,再用 31 減掉 ffs
即可得到 fls
。
在教材〈解讀計算機編碼〉中,有描述不需要分支的設計,當 INT32_MIN <= (b - a) <= INT32_MAX
條件成立時,可以使用 bitwise 操作改寫分支。
i_sqrt
__ffs
在 Linux 核心中, block 這個目錄下的 blk-wbt.c
有使用到整數平方根的操作,使用的函式為 rwb_arm_timer
。
blk-wbt.c
閱讀實作 writeback throttling
這個機制的作者 Jens Axboe 的 commit messages , throttling 這個機制最主要是讓背景執行的 buffered writeback 不會影響到其他正在執行的程式,作者發現在執行大量的 buffered writeback 時,他想要開啟 Chrome 會打不開。
But for as long as I can remember, heavy buffered writers have not behaved like that. For instance, if I do something like this:
$ dd if=/dev/zero of=foo bs=1M count=10k
on my laptop, and then try and start chrome, it basically won't start
before the buffered writeback is done. Or, for server oriented
workloads, where installation of a big RPM (or similar) adversely
impacts database reads or sync writes. When that happens, I get people
yelling at me.
這個機制有點像是 CoDel networking scheduling algorithm , blk-wb
監控一段時間中的最小延遲,如果這段時間中,有最小延遲超過設定的目標,就增加 scaling step
與壓縮佇列的深度,接著將監控的時間縮小 100 / sqrt(scaling step + 1)
。其中的整數平方根運算對應的程式碼在 /lib/math/int_sqrt.c
,其實作的演算法也是使用 digit-by-digit calculation 。
int_sqrt