Linux kernel中 __bitmap_weight函数的理解

来源:互联网 发布:大数据安全分析 编辑:程序博客网 时间:2024/05/21 12:29

对Linux kernel中 __bitmap_weight函数的理解 

int __bitmap_weight(const unsigned long *bitmap, int bits){int k, w = 0, lim = bits/BITS_PER_LONG;for (k = 0; k < lim; k++)w += hweight_long(bitmap[k]);if (bits % BITS_PER_LONG)w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));return w;}

static inline unsigned long hweight_long(unsigned long w){return sizeof(w) == 4 ? hweight32(w) : hweight64(w);}

hweight32函数和hweigh64函数是一样的

/**
 * hweightN - returns the hamming weight of a N-bit word
 * @x: the word to weigh
 *
 * The Hamming Weight of a number is the total number of bits set in it.
 */

求32位二进制数中的'1'的个数:

static inline unsigned int hweight32(unsigned int w)

{

unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);

res = (res & 0x33333333) + ((res >> 2) & 0x33333333);

res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);

res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);

return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);

}

分析:

这个函数的目的是求32位二进制数中的'1'的个数,我认为主要用到的思想就是算法中的"分治法"。以最为极端的情况来考虑

即w = 0xFFFFFFFF。

1).unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);

这里需要注意一点:w的类型为unsigned int(无符号整型,32位),因此,当w左移时,无论w的最高位是否为1,高位都用0补充。

w = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 UL

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

[array32] 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

res = ( 0xFFFFFFFF & 0x55555555 ) + ( ( 0xFFFFFFFF >> 1 ) & 0x55555555 )

= 0x55555555 + ( 0x7FFFFFFF & 0x55555555 )

= 0x55555555 + 0x55555555

= 0xAAAAAAAA

= 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 UL

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

[array16] 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

[array]是我为这个32位数标注的组号。

w当然就是一个有32个元素的组,我的目的不是要找到这32个元素中有多少个"1"么?好了,这里用到的最重要的思想就是:相邻组相加!!注意相邻组不是相邻位。第一次,相邻组就是1+2,3+4,5+6,... 31+32,这样加过来就从array32变成了array16了,函数的第一条语句相当于执行了16个运算!!!!

这里用图表示会更加形象:

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

w = 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 UL

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

[array32] 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |

->+| ->+| ->+| ->+| ->+| ->+| ->+| ->+| ->+| ->+| ->+| ->+| ->+| ->+| ->+| ->+|

V V V V V V V V V V V V V V V V

---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --

res =1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 UL

---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --

[array16] 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

2). 如此将数组维度继续缩小,相邻组相加,这次是1+2, 3+4, 5+6, ... 15+16,这样将array16变为array8... 直到array中只剩下一个元素,所有的"1"就都加在了一起。

如图所示:

---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --

res = 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 UL

---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --

[array16] 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1

| | | | | | | | | | | | | | | |

-->+| -->+| --->+| -->+| -->+| --->+| -->+| --->+|

V V V V V V V V

---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- --

res = 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 UL

---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- --

[array8] 8 7 6 5 4 3 2 1

| | | | | | | |

--------->+| --------->+| --------->+| --------->+|

V V V V

------------------------- ------------------------ ------------------------ ------------------------ --

res = 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 UL

------------------------- ------------------------ ------------------------ ------------------------ --

[array4] 4 3 2 1

| | | |

---------------------->+| ----------------------->+|

V V

-------------------------------------------------- --------------------------------------------------- --

res = 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 UL

-------------------------------------------------- --------------------------------------------------- --

[array2] 2 1

| |

--------------------------------------------------->+|

V

------------------------------------------------------------------------------------------------------ --

res = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 UL

------------------------------------------------------------------------------------------------------ --

[array1] 1

|

V

32

这样一来,五条语句相当于执行了16+8+4+2+1 = 31个运算了!!!!

下面是我自己写的一个模仿程序,以验证这个算法。该程序找到一个无符号8位数中"1"的个数

#include <stdio.h>

#include <linux/types.h>

static int my_hweight8( __u8 w )

{

__u8 ret = ( w & 0x55 ) + ( ( w >> 1 ) & 0x55 );

ret = ( ret & 0x33 ) + ( ( ret >> 2 ) & 0x33 );

ret = ( ret & 0x0F ) + ( ( ret >> 4 ) & 0x0F );

return (int)ret;

}__attribute__((always_inline))

int main()

{

int get_hweight8 = my_hweight8(0x6D);

printf("there are %d '1' in my 0x6D/n", get_hweight8);

return 0;

}

0 0
原创粉丝点击