contributed by < youjiaw >
1
Digit-by-digit calculation 提及了一種計算平方根的方式,其原理是將欲求平方根的 拆成:
並根據 將其擴展為:
以 n=2 舉例, 可以用下方的矩陣表示
將算式調整後可得
分別代表以下三個部分
接著令 ,則 就會是我們要求的平方根 N,因此我們需要找出每個 的值。
想檢測 的值是 還是 0,可以計算 與 的差值,若 就代表 為 ,否則為0,但是此方法每輪的運算成本太高了。
若是令
就可以透過紀錄 來取代 的計算。
最後將 拆為 、,可得
並藉由位元運算,由 、 推出下一輪的 、。
最後求得的 即為所求的 。
程式碼如下:
在確認 x
的範圍後,會使用三個變數,z
、m
與 b
,分別對應到先前的 、 與 。
在每輪迴圈中,無論 值為何, 都會除以 2, 則是除以 4,因此 AAAA
為 2,BBBB
為 1。
但是我還沒理解為什麼要做 & ~1UL
,相當於限制左移位元數為偶數,目前猜測是因為 ,所以 m
僅可能為 2 的偶數次方。
ffs 會回傳最低有效位元的索引,從 1 開始計算,若 x
為 0 則會回傳 0。因此可以不斷將 x
右移 ffs(x)
個位元,直到 x
為 0 時就停止,最後累計的位移次數減一就會是最高有效位元的索引。
因此加入以下程式碼
並更改迴圈條件為
而 fls 是直接回傳最高有效位元的索引
,因此更改如下
3
此程式碼目的是取得輸入值 i
在二進位表示中最高有效位元的索引。
版本一是將 i
()不斷右移一個位元直到為 0,此時右移次數即為 n,迴圈執行次數也為 n。
版本二則是依照 i
的大小,提供四種右移的方式,只要 i
大於 ,就一次右移 k 個位元,讓迴圈的執行次數可以小於 n。
版本三使用了 __builtin_clz
改寫,但因為輸入值不能為 0,所以先與 1 做 |
運算。
5
此程式碼以測驗三做延伸,計算。
若 (x > 0xFFFF) 回傳 1,則 r
的值為 10000
,因此會將 x
右移 16 個位元。
對應到測驗三的
而因為每次左移的位元數都不同,代表 r
和 shift
不會有相同位元都為 1 的情況,因此計算 result 的方式可以用 r |= shift
代替。
最後再判斷 x
是否大於 1。
最直覺的想法就是當 x
為 0 時減 0,其他情況減 1。目前採用下方的方法。
1