Skip to content

Commit

Permalink
Using faster popcnt function in pure Go
Browse files Browse the repository at this point in the history
  • Loading branch information
lemire committed May 7, 2014
1 parent 907fa09 commit 9d98cb6
Showing 1 changed file with 15 additions and 26 deletions.
41 changes: 15 additions & 26 deletions popcnt.go
Original file line number Diff line number Diff line change
@@ -1,64 +1,53 @@
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
}

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
}

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
}

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
}

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
}

0 comments on commit 9d98cb6

Please sign in to comment.