MIT HAKMEM演算法分析

2021-08-26 04:43:53 字數 2886 閱讀 8075

今天學習了一種很有趣的bitcount演算法——mit hakmem演算法。

本文中^表示乘方

問題需求:計算32位整型數中的'1'的個數

思路分析:

1.整型數i 的數值,實際上就是各位乘以權重——也就是乙個以2為底的多項式:

i= a0*2^0+a1*2^1+a2*2^2+...

因此,要求1的位數,實際上只要將各位消權:

i= a0+a1+a2+...

所得的係數和就是'1'的個數。

2.對任何自然數n的n次冪,用n-1取模得數為1,證明如下:

若 n^(k-1) % (n-1) = 1 成立

則 n^k % (n-1)= ((n-1)*n^(k-1) + n^(k-1)) % (n-1) = 0 + n^(k-1) % (n-1) = 1 也成立

又有 n^(1-1) % (n-1) = 1

故對任意非負整數n, n^n%(n-1)=1

3.因此,對乙個係數為的以n為底的多項式p(n), p(n)%(n-1) = (sum()) % (n-1);

如果能保證sum() < (n-1),則 p(n)%(n-1) = (sum()) ,也就是說,此時只要用n-1對多項式取模,就可以完成消權,得到係數和。

於是,問題轉化為,將以2為底的多項式轉化為以n為底的多項式,其中n要足夠大,使得n-1 > sum()恆成立。

32位整型數中ai=0或1,sum()<=32。n-1 > 32 ,n需要大於33。

因此取n=2^6=64>33作為新多項式的底。

4.將32位二進位制數的每6位作為乙個單位,看作以64為底的多項式:

i= t0*64^0 + t1*64^1 + t2*64^2 + t3*64^3 + ...

各項的係數ti就是每6位2進製數的值。

這樣,只要通過運算,將各個單位中的6位數變為這6位中含有的'1'的個數,再用63取模,就可以得到所求的總的'1'的個數。

5.取其中任意一項的6位數ti進行考慮,最簡單的方法顯然是對每次對1位進行mask然後相加,即

(ti>>5)&(000001) + (ti&>>4)(000001) + (ti>>3)&(000001) + (ti>>2)&(000001) + (ti>>1)&(000001) + ti&(000001)

其中000001位2進製數

由於ti最多含有6個1,因此上式最大值為000110,絕不會產生溢位,所以上式中的操作完全可以直接對整型數i 進行套用,操作過程中,t0~t6將並行地完成上式的運算。

注意:不能將&運算提取出來先+後&,想想為什麼。

因此,bit count的實現**如下:

view plain

intbitcount(unsigned

intn)

但mit hakmem最終的演算法要比上面的**更加簡單一些。

為什麼說上面的式子中不能先把(ti>>k)都先提取出來相加,然後再進行&運算呢?

因為用&(000001)進行mask後,產生的有效位只有1位,只要6位數中的'1'個數超過1位,那麼在"先加"的過程中,得數就會從最低位中向上溢位。

但是我們注意到,6位數中最多只有6個'1',也就是000110,只需要3位有效位。上面的式子實際上是以1位為單位提取出'1'的個數再相加求和求出6位中'1'的總個數的,所以用的是&(000001)。如果以3位為單位算出'1'的個數再進行相加的話,那麼就完全可以先加後mask。演算法如下:

tmp = (ti>>2)&(001001) + (ti>>1)&(001001) + ti&(001001)

(tmp + tmp>>3)&(000111)

c**:

view plain

intbitcount(unsigned

intn)

注:**中是使用8進製數進行mask的,11位8進製數為33位2進製數,多出一位,因此第一位八進位制數會把最高位捨去(7->3)以免超出int長度。

從第乙個版本到第二個實際上是乙個「提取公因式」的過程。用1組+, >>, &運算代替了3組。並且已經提取了"最大公因式"。然而這仍然不是最終的mit hakmem演算法,不過已經非常接近了,看看**吧。

mit hakmem演算法:

view plain

intbitcount(unsigned

intn)

又減少了一組+, >>, &運算。被優化的是3位2進製數「組」內的計算。再回到多項式,乙個3位2進製數是4a+2b+c,我們想要求的是a

+b+c,n>>1的結果是2a+b,n>>2的結果是a。

於是: (4a+2b+c) - (2a+b) - (a) = a + b + c

中間的mask是為了遮蔽"組間""串擾",即遮蔽掉從左邊組的低位移動過來的數。(見註解)

總結

第一次自己寫演算法分析,感覺收穫還是蠻大的。

看演算法的時候都是看這個演算法是如何工作的,寫的過程則是去模擬發現者的思路,看這個演算法是如何被推導出來的,把思路反過來又重新梳理了一遍。

最大的感慨是數學對於演算法的重要性。這個演算法最開始的思路就是多項式消權,並且貫穿了整個演算法推導和優化的過程。而第二步的必要條件則是對取模和冪運算關係的了解。優化的第一步用到了「提取公因式」思想,第二步則回歸到了多項式的基本運算。

其中除了取模和冪運算的知識不算太基礎以外,其他無一例外都是初中以內的數學知識與思想。特別是對2進製數本質的理解,所有人都清楚如何求得乙個二進位制整型數的數值,但是卻很少有人對其多項式本質始終保持著清晰的認識。

就是這些小得不能再小,基礎得不能再基礎的地方,決定了我們的水平。

註解(ps):劃線處感覺像是有點誤導(我沒看明白),按我自己的理解是因為2a+b的係數對應是3,所以此處的掩碼是3。(4a+2b+c) - (2a+b) - (a) 對應掩碼7,3,1。

MIT HAKMEM演算法分析

原文 簡化版 複習用 問題需求 計算32位整型數中的 1 的個數 思路分析 1.整型數 i 的數值,實際上就是各位乘以權重 也就是乙個以2為底的多項式 i a0 2 0 a1 2 1 a2 2 2 因此,要求1的位數,實際上只要將各位消權 i a0 a1 a2 所得的係數和就是 1 的個數。2.對任...

演算法分析 演算法的漸進效率分析

一般用於界定函式集合的上界,漸進表示式o g n 的含義就是,c為正常數,函式集合o中的元素的最大值不會超過c.g n f n o g n 的含義是,函式f n 的屬於集合o g n 因為函式集合o中的最大值為c.g n 所以f n 的最大值為c.g n 由於只是漸進的上界,所以當函式g n 的階數...

演算法和演算法分析

一 演算法的基本概述 演算法是為了解決某類問題而規定的乙個有限長的操作序列。乙個演算法必須滿足以下五個重要特性 1 有窮性2 確定性3 可行性 4 有輸入5 有輸出 二 設計演算法的原則 1.正確性 2.可讀性 3 健壯性 4.高效率與低儲存量需求 三 演算法的時間複雜度簡介 語句頻度 語句重複執行...