问题描述
我正在使用 big.Int
并且需要测试 0.现在,我正在使用 zero = big.NewInt(0)
和 Cmp(zero)==0
工作正常,但我想知道是否有专门针对 0 的更快方法(我需要这个程序非常快)?
I'm working with big.Int
s and need to test for 0. Right now, I'm using zero = big.NewInt(0)
and Cmp(zero)==0
which works fine, but I was wondering if there's a quicker way specifically for 0 (I need this program to be very fast)?
推荐答案
big.Int
暴露 Int.Bits()
访问表示的原始字节,它是一个切片,它共享相同的底层数组:不复制返回的切片.所以它很快.它暴露于支持实现缺少的低级 Int 功能".
完美,正是我们想要的.
Perfect, exactly what we want.
big.Int
的文档还指出Int 的零值表示值 0".因此,在零值(代表 0
)中,切片将为空(切片的零值是 nil
和 nil
切片的长度是 0
).我们可以简单地检查一下:
Documentation of big.Int
also states that "the zero value for an Int represents the value 0". So in the zero value (which represents 0
) the slice will be empty (zero value for slices is nil
and the length of a nil
slice is 0
). We can simply check that:
if len(i1.Bits()) == 0 {
}
另请注意,有一个 Int.BitLen()
函数返回此值,这也说明0 的位长为 0".所以我们也可以这样使用:
Also note that there is an Int.BitLen()
function returning this, which also states that "the bit length of 0 is 0". So we may also use this:
if i1.BitLen() == 0 {
}
让我们对这些解决方案进行基准测试:
Let's benchmark these solutions:
func BenchmarkCompare(b *testing.B) {
zero := big.NewInt(0)
i1 := big.NewInt(1)
i2 := big.NewInt(0)
for i := 0; i < b.N; i++ {
if i1.Cmp(zero) == 0 {
}
if i2.Cmp(zero) == 0 {
}
}
}
func BenchmarkBits(b *testing.B) {
i1 := big.NewInt(1)
i2 := big.NewInt(0)
for i := 0; i < b.N; i++ {
if len(i1.Bits()) == 0 {
}
if len(i2.Bits()) == 0 {
}
}
}
func BenchmarkBitLen(b *testing.B) {
i1 := big.NewInt(1)
i2 := big.NewInt(0)
for i := 0; i < b.N; i++ {
if i1.BitLen() == 0 {
}
if i2.BitLen() == 0 {
}
}
}
基准测试结果:
BenchmarkCompare-8 76975251 13.3 ns/op
BenchmarkBits-8 1000000000 0.656 ns/op
BenchmarkBitLen-8 1000000000 1.11 ns/op
获取位并将切片长度与 0
进行比较比将其与另一个表示 的
,使用 big.Int
进行比较快 20 倍0Int.BitLen()
也快 10 倍.
Getting the bits and comparing the slice length to 0
is 20 times faster than comparing it to another big.Int
representing 0
, using Int.BitLen()
is also 10 times faster.
可以使用类似的方法来测试 big.Int
值是否等于 1
,但可能不如测试零快:0
是最特殊的值.它的内部表示是一个 nil
切片,任何其他值都需要一个非 nil
切片.另外:0
还有一个特殊的属性:它的绝对值是它自己.
Something similar could be made to test if a big.Int
value equals to 1
, but probably not as fast as testing for zero: 0
is the most special value. Its internal representation is a nil
slice, any other value requires a non-nil
slice. Also: 0
has another special property: its absolute value is itself.
这个绝对值属性很重要,因为Int.Bits()
返回绝对值.因此,在非零值检查的情况下,仅检查位片是不够的,因为它不携带符号信息.
This absolute value property is important, because Int.Bits()
returns the absolute value. So in case of a non-zero value checking just the bits slice is insufficient, as it carries no sign information.
所以对1
的测试可以通过检查bits内容是否代表1
,并且符号为正来实现:
So testing for 1
can be implemented by checking if the bits content represents 1
, and the sign is positive:
func isOne(i *big.Int) bool {
bits := i.Bits()
return len(bits) == 1 && bits[0] == 1 && i.Sign() > 0
}
让我们对此进行基准测试,并将数字与 one := big.NewInt(1)
进行比较:
Let's benchmark this along with comparing the number to one := big.NewInt(1)
:
func BenchmarkCompareOne(b *testing.B) {
one := big.NewInt(1)
i1 := big.NewInt(0)
i2 := big.NewInt(1)
i3 := big.NewInt(2)
for i := 0; i < b.N; i++ {
if i1.Cmp(one) == 0 {
}
if i2.Cmp(one) == 0 {
}
if i3.Cmp(one) == 0 {
}
}
}
func BenchmarkBitsOne(b *testing.B) {
i1 := big.NewInt(0)
i2 := big.NewInt(1)
i3 := big.NewInt(2)
for i := 0; i < b.N; i++ {
if isOne(i1) {
}
if isOne(i2) {
}
if isOne(i3) {
}
}
}
以及基准测试结果:
BenchmarkCompareOne-8 58631458 18.9 ns/op
BenchmarkBitsOne-8 715606629 1.76 ns/op
还不错!我们测试 1 的方式再次快了 10 倍.
Not bad! Our way of testing for 1 is again 10 times faster.
这篇关于如果 big.Int 为 0,还有另一种测试方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!