big.Int是Go超大整型数据的结构。它可以进行超大收据的运算和比较等操作。
big.NewInt函数可以基于一个int64整型数据或整型字面量创建一个big.Int实例:
package main
import "math/big"
func main() {
var (
num int = 6
)
number1 := big.NewInt(int64(num))
number2 := big.NewInt(6)
}
big.Int实例的SetString方法可以通过字符串来创建一个big.Int实例。该方法返回两个数据,一个big.Int实例,和一个bool值用来表示成功还是失败。
package main
import (
"fmt"
"math/big"
)
func main() {
number, ok := new(big.Int).SetString("123000001230011", 10)
if !ok {
fmt.Println("create big.Int failed")
return
}
fmt.Println(number)
// 123000001230011
}
SetString允许指定数字的进制。创建的结果仍然是十进制的大整型数据:
package main
import (
"fmt"
"math/big"
)
func main() {
number, ok := new(big.Int).SetString("110000011010101010101", 2)
if !ok {
fmt.Println("create big.Int failed")
return
}
fmt.Println(number)
// 1586517
}
使用Add方法进行加法运算。需要注意的是Add方法返回一个big.Int实例,但通过地址不难看出,返回的实例与第一个加数相同。
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(123)
number2 := big.NewInt(456)
result := number1.Add(number1, number2)
fmt.Println(result, number1, number2)
// 579 579 456
println(result, number1, number2)
// 0x140000b0000 0x140000b0000 0x140000b0020
}
Sub方法进行减法运算,并与加法参数和返回值相似:
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(123)
number2 := big.NewInt(456)
result := number1.Sub(number1, number2)
fmt.Println(result, number1, number2)
// -333 -333 456
println(result, number1, number2)
// 0x14000132000 0x14000132000 0x14000132020
}
Mul用于乘法运算:
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(123)
number2 := big.NewInt(456)
result := number1.Mul(number1, number2)
fmt.Println(result, number1, number2)
// 56088 56088 456
println(result, number1, number2)
// 0x14000132000 0x14000132000 0x14000132020
}
Quo用于除法运算:
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(400)
number2 := big.NewInt(100)
result := number1.Quo(number1, number2)
fmt.Println(result, number1, number2)
// 4 4 100
println(result, number1, number2)
// 0x14000132000 0x14000132000 0x14000132020
}
如果除数为0,那么panic: division by zero被抛出:
package main
import (
"fmt"
"math/big"
)
func main() {
defer func() {
err := recover()
if err != nil {
fmt.Println(err)
// division by zero
}
}()
number1 := big.NewInt(7)
number2 := big.NewInt(0)
result := number1.Quo(number1, number2)
fmt.Println(result, number1, number2)
println(result, number1, number2)
}
Rem用于求余运算:
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(7)
number2 := big.NewInt(3)
result := number1.Rem(number1, number2)
fmt.Println(result, number1, number2)
// 1 1 3
println(result, number1, number2)
// 0x14000132000 0x14000132000 0x14000132020
}
如果除数为0,那么panic: division by zero被抛出:
package main
import (
"fmt"
"math/big"
)
func main() {
defer func() {
err := recover()
if err != nil {
fmt.Println(err)
// division by zero
}
}()
number1 := big.NewInt(7)
number2 := big.NewInt(0)
result := number1.Rem(number1, number2)
fmt.Println(result, number1, number2)
// 1 1 3
println(result, number1, number2)
// 0x14000132000 0x14000132000 0x14000132020
}
Abs方法获取big.Int实例的绝对值,返回的值仍然是一个big.Int实例:
package main
import (
"fmt"
"math/big"
)
func main() {
number := big.NewInt(-7)
result := number.Abs(number)
fmt.Println(result, number)
// 7 7
println(result, number)
// 0x14000132000 0x14000132000
}
Cmp方法用于比较两个big.Int实例的数值大小,CmpAbs方法用于比较两个big.Int实例数值绝对值大小。
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(200)
number2 := big.NewInt(500)
number3 := big.NewInt(200)
result := number1.Cmp(number2)
fmt.Println(result)
// -1
result = number2.Cmp(number3)
fmt.Println(result)
// 1
result = number1.Cmp(number3)
fmt.Println(result)
// 0
number4 := big.NewInt(-200)
result = number4.CmpAbs(number1)
fmt.Println(result)
// 0
}
Lsh方法进行位左移运算,Rsh方法进行位右移运算。
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(4)
// same as 4 << 1
result := number1.Lsh(number1, 1)
fmt.Println(result, number1) // 8 8
println(result, number1) // 0x14000132000 0x14000132000
number2 := big.NewInt(-4)
// same as -4 >> 1
result = number2.Rsh(number2, 1)
fmt.Println(result, number2) // -2 -2
println(result, number2) // 0x14000128020 0x14000128020
}
And方法进行与运算:
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(9)
number2 := big.NewInt(3)
// Same as 9 & 3
result := number1.And(number1, number2)
fmt.Println(result, number1, number2) // 1 1 3
println(result, number1, number2) // 0x14000132000 0x14000132000 0x14000132020
}
Or方法进行或运算:
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(5)
number2 := big.NewInt(3)
// Same as 5 | 3
result := number1.Or(number1, number2)
fmt.Println(result, number1, number2) // 7 7 3
println(result, number1, number2) // 0x14000132000 0x14000132000 0x14000132020
}
Xor方法进行亦或运算:
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(5)
number2 := big.NewInt(3)
// Same as 5 ^ 3
result := number1.Xor(number1, number2)
fmt.Println(result, number1, number2) // 6 6 3
println(result, number1, number2) // 0x14000132000 0x14000132000 0x14000132020
}
Not方法进行非运算:
package main
import (
"fmt"
"math/big"
)
func main() {
number := big.NewInt(7)
result := number.Not(number)
fmt.Println(result, number) // -8, -8
println(result, number) // 0x14000132000 0x14000132000
}
c = a &^ b
b转换为二进制后,值为1的位置对应c的位置为0,c中剩余比特值与a对应位置的比特值相等。
例如 0110 &^ 1011 = 0100
在big.Int实例中,提供了AndNot方法来执行按位清除运算:
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(5)
number2 := big.NewInt(11)
// Same as 5 &^ 11
result := number1.AndNot(number1, number2)
fmt.Println(result, number1, number2) // 4 4 11
println(result, number1, number2) // 0x14000132000 0x14000132000 0x14000132020
}
Sqrt方法提供了开方运算,并返回结果的绝对值。其返回值也是一个big.Int实例:
package main
import (
"fmt"
"math/big"
)
func main() {
number := big.NewInt(9)
result := number.Sqrt(number)
fmt.Println(result, number) // 3 3
println(result, number) // 0x14000128000 0x14000128000
}
如果被开方的结果不能用一个整数来表示,那么Sqrt方法返回一个最接近该值的整数。因此在涉及高精度计算时,不建议采用Sqrt方法。
package main
import (
"fmt"
"math/big"
)
func main() {
number := big.NewInt(7)
result := number.Sqrt(number)
fmt.Println(result, number) // 2 2
println(result, number) // 0x14000128000 0x14000128000
}
如果被开方的数字是个负数,那么panic会被抛出:
package main
import (
"fmt"
"math/big"
)
func main() {
number := big.NewInt(-9) // panic: square root of negative number
result := number.Sqrt(number)
fmt.Println(result, number)
println(result, number)
}
big.Int提供了一些类型转换的API,可供使用者将big.Int实例转换成期望的结果。
可使用String方法或fmt包中的格式化函数将big.Int转换成字符串:
package main
import (
"fmt"
"math/big"
)
func main() {
number := big.NewInt(531)
numberString := number.String()
fmt.Println(numberString)
// 531
numberString = fmt.Sprint(number)
fmt.Println(numberString)
// 531
}
Int64方法将big.Int实例转换为int64整数。
package main
import (
"fmt"
"math/big"
)
func main() {
number := big.NewInt(531)
number64 := number.Int64()
fmt.Println(number64)
// 531
}
如果big.Int表示的数据超出int64的最大范围(-9223372036854775808 ~ 9223372036854775807),转换的结果是不准确的。
package main
import (
"fmt"
"math/big"
)
func main() {
number, ok := new(big.Int).SetString("9223372036854775809", 10)
if !ok {
fmt.Println("create big.Int failed")
return
}
number64 := number.Int64()
fmt.Println(number64)
// -9223372036854775807
}
为了避免这种情况的发生,我们可以使用IsInt64方法判断big.Int实例是否可以正确转换成int64:
package main
import (
"fmt"
"math/big"
)
func main() {
number, ok := new(big.Int).SetString("9223372036854775809", 10)
if !ok {
fmt.Println("create big.Int failed")
return
}
if !number.IsInt64() {
fmt.Println("can not be represented as an int64")
return
}
// ...
}
big.Int提供了Uint64和IsUint64方法,用来将big.Int实例转换为uint64类型和判断是否可以转换。其用法与Int64和IsInt64类似,这里不再赘述。
使用Bytes方法将big.Int实例的绝对值转换为[]byte:
package main
import (
"fmt"
"math/big"
)
func main() {
number1 := big.NewInt(512)
fmt.Println(number1.Bytes())
// [2 0]
number2 := big.NewInt(-512)
fmt.Println(number2.Bytes())
// [2 0]
}
BitLen方法返回一个int数值表示big.Int实例绝对值的比特长度:
package main
import (
"fmt"
"math/big"
)
func main() {
number := big.NewInt(8)
fmt.Println(number.BitLen()) // 4
}