-
漢明重量
鎖定
- 中文名
- 漢明重量
- 本 質
- 一串符號中非零符號的個數
- 特 點
- 等於同長度全零符號串的漢明距離
目錄
- 1 SWAR算法“計算漢明重量”
- 2 實現
漢明重量SWAR算法“計算漢明重量”
第一步:
計算出來的值i的二進制可以按每2個二進制位為一組進行分組,各組的十進制表示的就是該組的漢明重量。
第二步:
計算出來的值i的二進制可以按每4個二進制位為一組進行分組,各組的十進制表示的就是該組的漢明重量。
第三步:
計算出來的值i的二進制可以按每8個二進制位為一組進行分組,各組的十進制表示的就是該組的漢明重量。
第四步:
i * (0x01010101)計算出漢明重量並記錄在二進制的高八位,>>24語句則通過右移運算,將漢明重量移到最低八位,最後二進制對應的十進制數就是漢明重量。
算法時間複雜度是O(1)的。
相關代碼
// 計算32位二進制的漢明重量 int32_t swar(int32_t i) { i = (i & 0x55555555) + ((i >> 1) & 0x55555555); i = (i & 0x33333333) + ((i >> 2) & 0x33333333); i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F); i = (i * (0x01010101) >> 24); return i }
漢明重量實現
在密碼學以及其它應用中經常需要計算數據位中1的個數,針對如何高效地實現人們已經廣泛地進行了研究。一些處理器使用單個的命令進行計算,另外一些根據數據位向量使用並行運算進行處理。對於沒有這些特性的處理器來説,已知的最好解決辦法是按照樹狀進行相加。例如,要計算二進制數A=0110110010111010中1的個數,這些運算可以表示為圖一:
這裏的運算是用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。例如圖二:
//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;