[英]Is there a big.BitCount?
Is there an already-written BitCount
method for big.Int? BitCount
是否已经编写了BitCount
方法? There doesn't seem to be one in math/big. 数学/大数学似乎没有一个。
Obviously I will write one myself if not - does anyone have one already written? 显然,我会自己写一个-有人写过吗?
I want the number of set bits in the number. 我想要数量中的设定位数。 Like Java BigInteger.bitCount() .
像Java BigInteger.bitCount()一样 。
As already mentioned, for quick efficient raw access to the underlying bits of a big.Int
you want to use big.Bits
. 如前所述,要快速有效地原始访问
big.Int
的基础位,您需要使用big.Bits
。 Also, quicker than either an 8 bit lookup table or a simple loop is to use one of well know 64 bit methods of counting bits (aka Hamming weight ). 而且,比使用8位查找表或简单循环更快的方法是,使用众所周知的64位计数方法之一(又称汉明权重 )。 Even faster, you could use an assembly implementation of
popcount
that uses a native CPU instruction ¹. 甚至更快,您可以使用使用本机CPU指令 ¹的
popcount
汇编实现。
Without using assembly, or catering to special cases where it's known there are few bits set, this is likely one of the faster/fastest Go implementations (it could be made faster on 32 bit machines by using uint32
and adjusting the popcount
function accordingly): 如果不使用汇编程序,或者不满足已知的特殊情况(设置的位数很少),则这可能是最快/最快的Go实现之一(可以通过使用
uint32
并相应地调整popcount
函数在32位计算机上更快地实现):
func BitCount(n *big.Int) int {
count := 0
for _, v := range n.Bits() {
count += popcount(uint64(v))
}
return count
}
// Straight and simple C to Go translation from https://en.wikipedia.org/wiki/Hamming_weight
func popcount(x uint64) int {
const (
m1 = 0x5555555555555555 //binary: 0101...
m2 = 0x3333333333333333 //binary: 00110011..
m4 = 0x0f0f0f0f0f0f0f0f //binary: 4 zeros, 4 ones ...
h01 = 0x0101010101010101 //the sum of 256 to the power of 0,1,2,3...
)
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 int((x * h01) >> 56) //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
}
Benchmarks and comparisons of this and other implementations presented here is available in full on GitHub gist . 此处提供的此实现和其他实现的基准测试和比较可在GitHub gist上完整获得。
¹ Such as the one added in Go1.9 ; ¹如Go1.9中添加的那一项 ; the updated gist shows it is ~3× faster than the previous best I had.
更新的要点显示它比我以前的最佳速度快约3倍。
I put one together myself - note that this does not take into account the sign of the number. 我自己整理了一个-请注意,这并未考虑数字的符号。 This returns the bit count of the the raw bytes behind the
big.Int
. 这将返回
big.Int
后面的原始字节的big.Int
。
// How many bits?
func BitCount(n big.Int) int {
var count int = 0
for _, b := range n.Bytes() {
count += int(bitCounts[b])
}
return count
}
// The bit counts for each byte value (0 - 255).
var bitCounts = []int8{
// Generated by Java BitCount of all values from 0 to 255
0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4,
2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4,
2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4,
2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6,
4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4,
2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6,
4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5,
3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6,
4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6,
4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7,
5, 6, 6, 7, 6, 7, 7, 8,
}
FYI, the following solution is simpler and faster than the original solution provided here: 仅供参考,以下解决方案比此处提供的原始解决方案更简单,更快捷:
func BitCountFast(z *big.Int) int {
var count int
for _, x := range z.Bits() {
for x != 0 {
x &= x-1
count++
}
}
return count
}
It outperforms the original solution by 5x on my machine: 在我的机器上,它的性能比原始解决方案高出5倍:
BenchmarkBitCountFast-4 100000000 19.5 ns/op 0 B/op 0 allocs/op
BenchmarkBitCountOrig-4 20000000 96.1 ns/op 16 B/op 1 allocs/op
You can use now (as of Go 1.9) the math/bits
library that implements some useful functions that deal with bit-related computations. 现在(从1.9版开始),您可以使用
math/bits
库,该库实现一些处理与位相关的计算的有用函数。 Concretely, you can iterate through the result of big.Int.Bits
and call the bits.OnesCount
function. 具体来说,您可以遍历
big.Int.Bits
的结果并调用bits.OnesCount
函数。
Here is an example: 这是一个例子:
package main
import (
"fmt"
"math/big"
"math/bits"
)
func BitCount(z *big.Int) int {
var count int
for _, x := range z.Bits() {
count += bits.OnesCount(uint(x))
}
return count
}
func PrintBinary(z *big.Int) {
for _, x := range z.Bits() {
fmt.Printf("%064b\n", x)
}
}
func main() {
a := big.NewInt(1 << 60 - 1)
b := big.NewInt(1 << 61 - 1)
c := big.NewInt(0)
c = c.Mul(a, b)
fmt.Println("Value in binary format:")
PrintBinary(c)
fmt.Println("BitCount:", BitCount(c))
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.