From 9d98cb66307efd37f028e50ab57c2182874a5bfc Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Wed, 7 May 2014 14:40:40 -0400 Subject: [PATCH] Using faster popcnt function in pure Go --- popcnt.go | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/popcnt.go b/popcnt.go index 36be0d1..76577a8 100644 --- a/popcnt.go +++ b/popcnt.go @@ -1,32 +1,21 @@ package bitset -// From Wikipedia: http://en.wikipedia.org/wiki/Hamming_weight -const m1 uint64 = 0x5555555555555555 //binary: 0101... -const m2 uint64 = 0x3333333333333333 //binary: 00110011.. -const m4 uint64 = 0x0f0f0f0f0f0f0f0f //binary: 4 zeros, 4 ones ... -const m8 uint64 = 0x00ff00ff00ff00ff //binary: 8 zeros, 8 ones ... -const m16 uint64 = 0x0000ffff0000ffff //binary: 16 zeros, 16 ones ... -const m32 uint64 = 0x00000000ffffffff //binary: 32 zeros, 32 ones -const hff uint64 = 0xffffffffffffffff //binary: all ones -const h01 uint64 = 0x0101010101010101 //the sum of 256 to the power of 0,1,2,3... - -// From Wikipedia: count number of set bits. -// This is algorithm popcount_2 in the article retrieved May 9, 2011 - -func popcount_2(x uint64) uint64 { - 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 & 0x7f +// bit population count, take from +// https://code.google.com/p/go/issues/detail?id=4988#c11 +// credit: https://code.google.com/u/arnehormann/ +func popcount(x uint64) (n uint64) { + x -= (x >> 1) & 0x5555555555555555 + x = (x>>2)&0x3333333333333333 + x&0x3333333333333333 + x += x >> 4 + x &= 0x0f0f0f0f0f0f0f0f + x *= 0x0101010101010101 + return x >> 56 } func popcntSliceGo(s []uint64) uint64 { cnt := uint64(0) for _, x := range s { - cnt += popcount_2(x) + cnt += popcount(x) } return cnt } @@ -34,7 +23,7 @@ func popcntSliceGo(s []uint64) uint64 { func popcntMaskSliceGo(s, m []uint64) uint64 { cnt := uint64(0) for i := range s { - cnt += popcount_2(s[i] &^ m[i]) + cnt += popcount(s[i] &^ m[i]) } return cnt } @@ -42,7 +31,7 @@ func popcntMaskSliceGo(s, m []uint64) uint64 { func popcntAndSliceGo(s, m []uint64) uint64 { cnt := uint64(0) for i := range s { - cnt += popcount_2(s[i] & m[i]) + cnt += popcount(s[i] & m[i]) } return cnt } @@ -50,7 +39,7 @@ func popcntAndSliceGo(s, m []uint64) uint64 { func popcntOrSliceGo(s, m []uint64) uint64 { cnt := uint64(0) for i := range s { - cnt += popcount_2(s[i] | m[i]) + cnt += popcount(s[i] | m[i]) } return cnt } @@ -58,7 +47,7 @@ func popcntOrSliceGo(s, m []uint64) uint64 { func popcntXorSliceGo(s, m []uint64) uint64 { cnt := uint64(0) for i := range s { - cnt += popcount_2(s[i] ^ m[i]) + cnt += popcount(s[i] ^ m[i]) } return cnt }