// 笨办法 funcfindBitCount1(x uint64)int{ var res int for x > 0 { if x & (x-1) == (x-1) { res++ } x = x >> 1 } return res }
funcfindBitCount2(x uint64)int{ x = x & 0x5555555555555555 + x >> 1 & 0x5555555555555555 x = x & 0x3333333333333333 + x >> 2 & 0x3333333333333333 x = x & 0x0f0f0f0f0f0f0f0f + x >> 4 & 0x0f0f0f0f0f0f0f0f x = x & 0x00ff00ff00ff00ff + x >> 8 & 0x00ff00ff00ff00ff x = x & 0x0000ffff0000ffff + x >> 16 & 0x0000ffff0000ffff x = x & 0x00000000ffffffff + x >> 32 & 0x00000000ffffffff returnint(x) }
funcfindBitCount3(x uint64)int{ x = x & 0x5555555555555555 + x >> 1 & 0x5555555555555555 x = x & 0x3333333333333333 + x >> 2 & 0x3333333333333333 x = x & 0x0f0f0f0f0f0f0f0f + x >> 4 & 0x0f0f0f0f0f0f0f0f x = x >> 8 x = x >> 16 x = x >> 32 // & (1<<7 - 1) 确保1的个数不会超过64个 returnint(x) & (1<<7 - 1) }
funcBenchmarkFindBitCount(b *testing.B) { cases := []struct{ Num uint64 Ept int }{ {Num: uint64(0), Ept: 0}, {Num:uint64(1<<64-1), Ept:64}, {Num:uint64(64), Ept:1}, {Num:uint64(1<<32), Ept:1}, {Num:uint64(167381424443), Ept:23}, } for _, c := range cases { b.Run(fmt.Sprintf("Func1 with Num:%v", c.Num), func(b *testing.B){ for i := 0; i <b.N; i++ { findBitCount1(c.Num) } }) b.Run(fmt.Sprintf("Func2 with Num:%v", c.Num), func(b *testing.B){ for i := 0; i <b.N; i++ { findBitCount2(c.Num) } }) b.Run(fmt.Sprintf("Func3 with Num:%v", c.Num), func(b *testing.B){ for i := 0; i <b.N; i++ { findBitCount3(c.Num) } }) b.Run(fmt.Sprintf("OnesCount64 with Num:%v", c.Num), func(b *testing.B){ for i := 0; i <b.N; i++ { bits.OnesCount64(c.Num) } }) } }
133// OnesCount64 returns the number of one bits ("population count") in x. 134funcOnesCount64(x uint64)int { 135// Implementation: Parallel summing of adjacent bits. 136// See "Hacker's Delight", Chap. 5: Counting Bits. 137// The following pattern shows the general approach: 138// 139// x = x>>1&(m0&m) + x&(m0&m) 140// x = x>>2&(m1&m) + x&(m1&m) 141// x = x>>4&(m2&m) + x&(m2&m) 142// x = x>>8&(m3&m) + x&(m3&m) 143// x = x>>16&(m4&m) + x&(m4&m) 144// x = x>>32&(m5&m) + x&(m5&m) 145// return int(x) 146// 147// Masking (& operations) can be left away when there's no 148// danger that a field's sum will carry over into the next 149// field: Since the result cannot be > 64, 8 bits is enough 150// and we can ignore the masks for the shifts by 8 and up. 151// Per "Hacker's Delight", the first line can be simplified 152// more, but it saves at best one instruction, so we leave 153// it alone for clarity. 154const m = 1<<64 - 1 155 x = x>>1&(m0&m) + x&(m0&m) 156 x = x>>2&(m1&m) + x&(m1&m) 157 x = (x>>4 + x) & (m2 & m) 158 x += x >> 8 159 x += x >> 16 160 x += x >> 32 161returnint(x) & (1<<7 - 1) 162 }