计算机科学

首页 > 计算机科学

汉明重量

2018-08-27 10:32:59     所属分类:编码理论

汉明重量是一串符号中非零符号的个数。因此它等同于同样长度的全零符号串的汉明距离。在最为常见的数据位符号串中,它是1的个数。

字符 字符串 汉明重量
0,1 11101 4
0,1 11101000 4
0,1 00000000 0
' ',a-z hello world 11

目录

  • 1 历史及应用
  • 2 高效实现
  • 3 参见
  • 4 外部链接

历史及应用

汉明重量是以理查德·卫斯里·汉明的名字命名的,它在包括信息论、编码理论、密码学等多个领域都有应用。

高效实现

在密码学以及其它应用中经常需要计算数据位中1的个数,针对如何高效地实现人们已经广泛地进行了研究。一些处理器使用单个的命令进行计算,另外一些根据数据位向量使用并行运算进行处理。对于没有这些特性的处理器来说,已知的最好解决办法是按照树状进行相加。例如,要计算二进制数A=0110110010111010中1的个数,这些运算可以表示为:

符号 二进制 十进制 注释
A 0110110010111010 原始数据
B = A & 01 01 01 01 01 01 01 01 01 00 01 00 00 01 00 00 1,0,1,0,0,1,0,0 A隔一位检验
C = (A >> 1) & 01 01 01 01 01 01 01 01 00 01 01 00 01 01 01 01 0,1,1,0,1,1,1,1 A中剩余的数据位
D = B + C 01 01 10 00 01 10 01 01 1,1,2,0,1,2,1,1 A中每个双位段中1的个数列表
E = D & 0011 0011 0011 0011 0001 0000 0010 0001 1,0,2,1 D中数据隔一位检验
F = (D >> 2) & 0011 0011 0011 0011 0001 0010 0001 0001 1,2,1,1 D中剩余数据的计算
G = E + F 0010 0010 0011 0010 2,2,3,2 A中4位数据段中1的个数列表
H = G & 00001111 00001111 00000010 00000010 2,2 G中数据隔一位检验
I = (G >> 4) & 00001111 00001111 00000010 00000011 2,3 G中剩余数据的计算
J = H + I 00000100 00000101 4,5 A中8位数据段中1的个数列表
K = J & 0000000011111111 0000000000000101 5 J中隔一位检验
L = (J >> 8) & 0000000011111111 0000000000000100 4 J中剩余数据的检验
M = K + L 0000000000001001 9 最终答案

这里的运算是用C语言表示的,所以X >> Y表示X右移Y位,X & Y表示X与Y的位与,+表示普通的加法。基于上面所讨论的思想的这个问题的最好算法列在这里:

//types and constants used in the functions below

typedef unsigned __int64 uint64;  //assume this gives 64-bits
const uint64 m1 = 0x5555555555555555; //binary: 0101...
const uint64 m2 = 0x3333333333333333; //binary: 00110011..
const uint64 m4 = 0x0f0f0f0f0f0f0f0f; //binary:  4 zeros,  4 ones ...
const uint64 m8 = 0x00ff00ff00ff00ff; //binary:  8 zeros,  8 ones ...
const uint64 m16 = 0x0000ffff0000ffff; //binary: 16 zeros, 16 ones ...
const uint64 m32 = 0x00000000ffffffff; //binary: 32 zeros, 32 ones ...
const uint64 hff = 0xffffffffffffffff; //binary: all ones
const uint64 h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3...

//This is a naive implementation, shown for comparison,
//and to help in understanding the better functions.
//It uses 24 arithmetic operations (shift, add, and).
int popcount_1(uint64 x) {
    x = (x & m1 ) + ((x >>  1) & m1 ); //put count of each  2 bits into those  2 bits 
    x = (x & m2 ) + ((x >>  2) & m2 ); //put count of each  4 bits into those  4 bits 
    x = (x & m4 ) + ((x >>  4) & m4 ); //put count of each  8 bits into those  8 bits 
    x = (x & m8 ) + ((x >>  8) & m8 ); //put count of each 16 bits into those 16 bits 
    x = (x & m16) + ((x >> 16) & m16); //put count of each 32 bits into those 32 bits 
    x = (x & m32) + ((x >> 32) & m32); //put count of each 64 bits into those 64 bits 
    return x;
}

//This uses fewer arithmetic operations than any other known  
//implementation on machines with slow multiplication.
//It uses 17 arithmetic operations.
int popcount_2(uint64 x) {
    x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits
    x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits 
    x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits 
    x += x >>  8;  //put count of each 16 bits into their lowest 8 bits
    x += x >> 16;  //put count of each 32 bits into their lowest 8 bits
    x += x >> 32;  //put count of each 64 bits into their lowest 8 bits
    return x &0xff;
}

//This uses fewer arithmetic operations than any other known  
//implementation on machines with fast multiplication.
//It uses 12 arithmetic operations, one of which is a multiply.
int popcount_3(uint64 x) {
    x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits
    x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits 
    x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits 
    return (x * h01)>>56;  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ... 
}

在最坏的情况下,上面的实现是所有已知算法中表现最好的。但是,如果已知大多数数据位是0的话,那么还有更快的算法。这些更快的算法是基于这样一种事实即X与X-1相得到的最低位永远是0。例如:

Expression Value
X 0 1 0 0 0 1 0 0 0 1 0 0 0 0
X-1 0 1 0 0 0 1 0 0 0 0 1 1 1 1
X & (X-1) 0 1 0 0 0 1 0 0 0 0 0 0 0 0

减1操作将最右边的符号从0变到1,从1变到0,操作将会移除最右端的1。如果最初X有N个1,那么经过N次这样的迭代运算,X将减到0。下面的算法就是根据这个原理实现的。

//This is better when most bits in x are 0
//It uses 3 arithmetic operations and one comparison/branch per "1" bit in x.
int popcount_4(uint64 x) {
    uint64 count;
    for (count=0; x; count++)
        x &= x-1;
    return count;
}

//This is better if most bits in x are 0.
//It uses 2 arithmetic operations and one comparison/branch  per "1" bit in x.
//It is the same as the previous function, but with the loop unrolled.
#define f(y) if ((x &= x-1) == 0) return y;
int popcount_5(uint64 x) {
    if (x == 0) return 0;
    f( 1) f( 2) f( 3) f( 4) f( 5) f( 6) f( 7) f( 8)
    f( 9) f(10) f(11) f(12) f(13) f(14) f(15) f(16)
    f(17) f(18) f(19) f(20) f(21) f(22) f(23) f(24)
    f(25) f(26) f(27) f(28) f(29) f(30) f(31) f(32)
    f(33) f(34) f(35) f(36) f(37) f(38) f(39) f(40)
    f(41) f(42) f(43) f(44) f(45) f(46) f(47) f(48)
    f(49) f(50) f(51) f(52) f(53) f(54) f(55) f(56)
    f(57) f(58) f(59) f(60) f(61) f(62) f(63)
    return 64;
}

//Use this instead if most bits in x are 1 instead of 0
#define f(y) if ((x |= x+1) == hff) return 64-y;

参见

  • 汉明距离

外部链接

  • Aggregate Magic Algorithms.优化汉明重量算法及其它算法解释(附源代码)。
  • HACKMEM item 169. Population count assembly code for the PDP/6-10.
  • Bit Twiddling Hacks带有源代码的几种汉明重量计算方法

感谢您的支持,我会继续努力的!

扫码支持
1分,2分不嫌少,钱不钱的无所谓,重要的是你的话语激励我前行!

愿你每天温暖如春!!!

显示全文

取消

感谢您的支持,我会继续努力的!

扫码支持
无需打赏可直接关闭阅读全文
1分,2分不嫌少,钱不钱的无所谓,重要的是你的话语激励我前行!

愿你每天温暖如春!!!


上一篇:信道编码
相关推荐