Go 有大的比特数吗?
是否已经为big.Int编写了Go 有大的比特数吗?,go,bitcount,Go,Bitcount,是否已经为big.Int编写了BitCount方法?数学/大数学似乎没有 显然,如果没有的话,我会自己写一本——有人已经写过了吗 我想要数字中的设定位数。比如。我自己把一个放在一起-注意这不考虑数字的符号。这将返回big.Int后面的原始字节的位计数 // How many bits? func BitCount(n big.Int) int { var count int = 0 for _, b := range n.Bytes() { count += in
BitCount
方法?数学/大数学似乎没有
显然,如果没有的话,我会自己写一本——有人已经写过了吗
我想要数字中的设定位数。比如。我自己把一个放在一起-注意这不考虑数字的符号。这将返回
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,
}
我自己把一个放在一起-注意这不考虑数字的符号。这将返回
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,
}
仅供参考,以下解决方案比此处提供的原始解决方案更简单、更快:
func BitCountFast(z *big.Int) int {
var count int
for _, x := range z.Bits() {
for x != 0 {
x &= x-1
count++
}
}
return count
}
在我的机器上,它的性能比原始解决方案高出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
仅供参考,以下解决方案比此处提供的原始解决方案更简单、更快:
func BitCountFast(z *big.Int) int {
var count int
for _, x := range z.Bits() {
for x != 0 {
x &= x-1
count++
}
}
return count
}
在我的机器上,它的性能比原始解决方案高出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
如前所述,为了快速有效地原始访问要使用的
big.Int
的底层位。
此外,比8位查找表或简单循环更快的是使用众所周知的64位计数方法(aka)。
甚至更快,您可以使用一个使用本机的popcount
程序集实现
如果不使用汇编,或者不满足已知设置的位很少的特殊情况,这可能是更快/最快的Go实现之一(在32位机器上,可以通过使用uint32
并相应调整popcount
功能来提高速度):
func位计数(n*big.Int)Int{
计数:=0
对于u,v:=范围n.位(){
计数+=popcount(uint64(v))
}
返回计数
}
//直接简单的C语言翻译https://en.wikipedia.org/wiki/Hamming_weight
func popcount(x uint64)int{
常数(
m1=0x5555//二进制:0101。。。
m2=0x3333//二进制:00110011。。
m4=0x0F0F//二进制:4个零,4个一。。。
h01=0x0101010101//256之和等于0,1,2,3的幂。。。
)
x-=(x>>1)&m1//将每2位的计数放入这2位中
x=(x&m2)+(x>>2)&m2)//将每4位的计数放入这4位中
x=(x+(x>>4))&m4//将每8位的计数放入这8位中
return int((x*h01)>>56)//返回前面提到的x+(x的左8位,以便快速有效地原始访问要使用的big.int
的底层位。
此外,比8位查找表或简单循环更快的是使用众所周知的64位计数方法(aka)。
甚至更快,您可以使用一个使用本机的popcount
程序集实现
如果不使用汇编,或者不满足已知设置的位很少的特殊情况,这可能是更快/最快的Go实现之一(在32位机器上,可以通过使用uint32
并相应调整popcount
功能来提高速度):
func位计数(n*big.Int)Int{
计数:=0
对于u,v:=范围n.位(){
计数+=popcount(uint64(v))
}
返回计数
}
//直接简单的C语言翻译https://en.wikipedia.org/wiki/Hamming_weight
func popcount(x uint64)int{
常数(
m1=0x5555//二进制:0101。。。
m2=0x3333//二进制:00110011。。
m4=0x0F0F//二进制:4个零,4个一。。。
h01=0x0101010101//256之和等于0,1,2,3的幂。。。
)
x-=(x>>1)&m1//将每2位的计数放入这2位中
x=(x&m2)+(x>>2)&m2)//将每4位的计数放入这4位中
x=(x+(x>>4))&m4//将每8位的计数放入这8位中
return int((x*h01)>>56)//返回x+(x的左8位,您现在可以使用(从Go 1.9开始)这个库来实现一些处理位相关计算的有用函数。具体地说,您可以迭代并调用函数的结果
以下是一个例子:
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))
}
主程序包
进口(
“fmt”
“数学/大”
“数学/比特”
)
func位计数(z*big.Int)Int{
变量计数整数
对于ux:=范围z.位(){
计数+=位。一个单位(uint(x))
}
返回计数
}
func PrintBinary(z*big.Int){
对于ux:=范围z.位(){
fmt.Printf(“%064b\n”,x)
}
}
func main(){
a:=big.NewInt(1您现在可以使用(从Go 1.9开始)实现一些有用函数的库,这些函数处理与位相关的计算。具体地说,您可以遍历函数的结果并调用函数
以下是一个例子:
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))
}
主程序包
进口(
“fmt”
“数学/大”
“数学/比特”
)
func位计数(z*big.Int)Int{
变量计数整数
对于ux:=范围z.位(){
计数+=位。一个单位(uint(x))
}
返回计数
}
func PrintBinary(z*big.Int){
对于ux:=范围z.位(){
fmt.Printf(“%064b\n”,x)
}
}
func main(){
a:=big.NewInt(1我认为如果您在这里使用int8
而不是int
,则缓存命中率会更高(4x?)。我认为如果您在这里使用int8
而不是int
,则缓存命中率会更高(4x?)缓存命中。速度更快的原因之一是返回对底层[]big.Word
的原始访问,而分配一个新的[]字节
。还要注意,这里的外部for
循环可以更快地使用标准32或64位运算来计算每个big.Word
(只是uintpttr
)和删除嵌套循环。例如,请参阅。(注意,我已将我以前的注释转化为)我的代码速度更快的另一个原因是基准测试中使用的稀疏位集:)使用密集位集时,您的解决方案速度更快