如果 big.Int 为 0,还有另一种测试方法吗?

lol*_*lad 4 comparison performance go bigint

我正在使用big.Ints 并且需要测试 0。现在,我正在使用zero = big.NewInt(0)并且Cmp(zero)==0效果很好,但我想知道是否有专门针对 0 的更快方法(我需要这个程序非常快)?

icz*_*cza 7

big.Int公开Int.Bits()访问表示的原始字节,它是一个切片,它共享相同的底层数组:不复制返回的切片。所以它很快。它暴露于“支持实现缺少的低级 Int 功能”

完美,正是我们想要的。

0. 测试 0

的文档big.Int还指出“Int 的零值表示值 0”。因此,在零值(表示0)中,切片将为空(切片的零值为 ,切片nil的长度nil0)。我们可以简单地检查一下:

if len(i1.Bits()) == 0 {
}
Run Code Online (Sandbox Code Playgroud)

另请注意,有一个Int.BitLen()返回 this的函数,它还指出“0 的位长为 0”。所以我们也可以这样使用:

if i1.BitLen() == 0 {
}
Run Code Online (Sandbox Code Playgroud)

让我们对这些解决方案进行基准测试:

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 {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

基准测试结果:

BenchmarkCompare-8      76975251            13.3 ns/op
BenchmarkBits-8         1000000000           0.656 ns/op
BenchmarkBitLen-8       1000000000           1.11 ns/op
Run Code Online (Sandbox Code Playgroud)

获取比特和切片长度比较0快20倍比比较它与另一个big.Int代表0,使用Int.BitLen()快10倍

1. 测试 1

可以做类似的事情来测试一个big.Int值是否等于1,但可能没有测试零那么快:0是最特殊的值。它的内部表示是一个nil切片,任何其他值都需要一个非nil切片。另外:0还有一个特殊的属性:它的绝对值就是它自己。

这个绝对值属性很重要,因为Int.Bits()返回绝对值。因此,在非零值检查的情况下,仅位片是不够的,因为它不携带符号信息。

因此1可以通过检查位内容是否代表1,并且符号为正来实现测试:

func isOne(i *big.Int) bool {
    bits := i.Bits()
    return len(bits) == 1 && bits[0] == 1 && i.Sign() > 0
}
Run Code Online (Sandbox Code Playgroud)

让我们对此进行基准测试,并将数字与 进行比较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) {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

以及基准测试结果:

BenchmarkCompareOne-8       58631458            18.9 ns/op
BenchmarkBitsOne-8          715606629            1.76 ns/op
Run Code Online (Sandbox Code Playgroud)

不错!我们测试 1 的方法又快10 倍

  • @lolad ...你就得到了它。查看编辑后的答案。 (2认同)