在go语言中我们知道整形只有byte、int32以及int64等而浮点数只有float32和float64基本数据类型。有时候根据需求需要使用大数操作,go中的big包中带了NewInt以及NewFloat,但是提供的api较少,可供初始化的只能使用基本数据类型。不能使用字符串进行初始化。于是本人参考java的大数类进行开发go-bigger并且提供丰富的API调用。github:
内置BigInteger结构体和BigDecimal结构体,包括简单的加减乘除取模等操作。对于高精度的浮点类型BigDecimal目前正在开发阶段,后续会陆续上线。
下面简单介绍用法:
1. 引入如下github模块
go get github.com/sineycoder/go-bigger
2. BigInteger
初始化BigInteger
a:=bigger.NewBigIntegerString("112233")
//或者
a:=bigger.NewBigIntegerLong(112233)
2.1 BigInteger的Add:
func main() {
a := big_integer.ValueOf(6782613786431)
b := big_integer.ValueOf(-678261378231)
res := a.Add(b)
fmt.Println(res.String())
}
结果: 6104352408200
2.2 BigInteger的Subtract:
func main() {
a := big_integer.ValueOf(6782613786431)
b := big_integer.ValueOf(-678261378231)
res := a.Subtract(b)
fmt.Println(res.String())
}
结果: 7460875164662
2.3 BigInteger的Divide:
func main() {
a := big_integer.ValueOf(6782613786431)
b := big_integer.ValueOf(-678261378231)
res := a.Divide(b)
fmt.Println(res.String())
}
结果: -10
2.4 BigInteger的Multiply:
func main() {
a := big_integer.ValueOf(6782613786431)
b := big_integer.ValueOf(-678261378231)
res := a.Multiply(b)
fmt.Println(res.String())
}
结果: -4600384974793271546583561
3. BigDecimal
BigDecimal初始化:目前仅支持字符串的初始化,可以满足大部分需求!
a:=bigger.NewBigDecimalString("112233.112")
3.1 BigDecimal的Add:
func BenchmarkBiggerFloatAdd(bb *testing.B) {
a := bigger.NewBigDecimalString("534151451245")
b := bigger.NewBigDecimalString("18979412")
a.Add(b)
}
3.2 BigDecimal的Substract:
func BenchmarkBiggerFloatSubtract(bb *testing.B) {
a := bigger.NewBigDecimalString("534151451245")
b := bigger.NewBigDecimalString("18979412")
a.Subtract(b)
}
3.3 BigDecimal的Multiply:
func BenchmarkBiggerFloatMultiply(bb *testing.B) {
a := bigger.NewBigDecimalString("534151451245")
b := bigger.NewBigDecimalString("18979412")
a.Multiply(b)
}
3.4 BigDecimal的Divide:
func BenchmarkBiggerFloatDivide(bb *testing.B) {
a := bigger.NewBigDecimalString("1")
b := bigger.NewBigDecimalString("3")
a.Divide(b, 5, bigger.ROUND_HALF_UP)
}
4. 与go内置函数性能对比
4.1 测试代码:
// testing Integer, bigger.bigInteger vs bigInt
func BenchmarkBiggerIntegerAdd(bb *testing.B) {
a := bigger.BigIntegerValueOf(types.Long(534151451245))
b := bigger.BigIntegerValueOf(types.Long(18979412))
a.Add(b)
}
func BenchmarkBigintIntegerAdd(bb *testing.B) {
a := big.NewInt(534151451245)
b := big.NewInt(18979412)
a.Add(a, b)
}
func BenchmarkBiggerIntegerSubtract(bb *testing.B) {
a := bigger.BigIntegerValueOf(types.Long(534151451245))
b := bigger.BigIntegerValueOf(types.Long(18979412))
a.Subtract(b)
}
func BenchmarkBigintIntegerSubtract(bb *testing.B) {
a := big.NewInt(534151451245)
b := big.NewInt(18979412)
a.Sub(a, b)
}
func BenchmarkBiggerIntegerMultiply(bb *testing.B) {
a := bigger.BigIntegerValueOf(types.Long(534151451245))
b := bigger.BigIntegerValueOf(types.Long(18979412))
a.Multiply(b)
}
func BenchmarkBigintIntegerMultiply(bb *testing.B) {
a := big.NewInt(534151451245)
b := big.NewInt(18979412)
a.Mul(a, b)
}
func BenchmarkBiggerIntegerDivide(bb *testing.B) {
a := bigger.BigIntegerValueOf(types.Long(534151451245))
b := bigger.BigIntegerValueOf(types.Long(18979412))
a.Divide(b)
}
func BenchmarkBigintIntegerDivide(bb *testing.B) {
a := big.NewInt(534151451245)
b := big.NewInt(18979412)
a.Div(a, b)
}
// testing Float, bigger.bigDecimal vs bigFloat
func BenchmarkBiggerFloatAdd(bb *testing.B) {
a := bigger.NewBigDecimalString("534151451245")
b := bigger.NewBigDecimalString("18979412")
a.Add(b)
}
func BenchmarkBigintFloatAdd(bb *testing.B) {
a := big.NewFloat(534151451245)
b := big.NewFloat(18979412)
a.Add(a, b)
}
func BenchmarkBiggerFloatSubtract(bb *testing.B) {
a := bigger.NewBigDecimalString("534151451245")
b := bigger.NewBigDecimalString("18979412")
a.Subtract(b)
}
func BenchmarkBigintFloatSubtract(bb *testing.B) {
a := big.NewFloat(534151451245)
b := big.NewFloat(18979412)
a.Sub(a, b)
}
func BenchmarkBiggerFloatMultiply(bb *testing.B) {
a := bigger.NewBigDecimalString("534151451245")
b := bigger.NewBigDecimalString("18979412")
a.Multiply(b)
}
func BenchmarkBigintFloatMultiply(bb *testing.B) {
a := big.NewFloat(534151451245)
b := big.NewFloat(18979412)
a.Mul(a, b)
}
func BenchmarkBiggerFloatDivide(bb *testing.B) {
a := bigger.NewBigDecimalString("1")
b := bigger.NewBigDecimalString("3")
a.Divide(b, 5, bigger.ROUND_HALF_UP)
}
func BenchmarkBigintFloatDivide(bb *testing.B) {
a := big.NewFloat(0.5)
b := big.NewFloat(0.4)
a.Quo(a, b)
}
4.2 结果输出:
BenchmarkBiggerIntegerAdd
BenchmarkBiggerIntegerAdd-12 1000000000 0.0000024 ns/op
BenchmarkBigintIntegerAdd
BenchmarkBigintIntegerAdd-12 1000000000 0.0000017 ns/op
BenchmarkBiggerIntegerSubtract
BenchmarkBiggerIntegerSubtract-12 1000000000 0.0000023 ns/op
BenchmarkBigintIntegerSubtract
BenchmarkBigintIntegerSubtract-12 1000000000 0.0000015 ns/op
BenchmarkBiggerIntegerMultiply
BenchmarkBiggerIntegerMultiply-12 1000000000 0.0000032 ns/op
BenchmarkBigintIntegerMultiply
BenchmarkBigintIntegerMultiply-12 1000000000 0.0000022 ns/op
BenchmarkBiggerIntegerDivide
BenchmarkBiggerIntegerDivide-12 1000000000 0.0000025 ns/op
BenchmarkBigintIntegerDivide
BenchmarkBigintIntegerDivide-12 1000000000 0.0000015 ns/op
BenchmarkBiggerFloatAdd
BenchmarkBiggerFloatAdd-12 1000000000 0.0000022 ns/op
BenchmarkBigintFloatAdd
BenchmarkBigintFloatAdd-12 1000000000 0.0000023 ns/op
BenchmarkBiggerFloatSubtract
BenchmarkBiggerFloatSubtract-12 1000000000 0.0000024 ns/op
BenchmarkBigintFloatSubtract
BenchmarkBigintFloatSubtract-12 1000000000 0.0000028 ns/op
BenchmarkBiggerFloatMultiply
BenchmarkBiggerFloatMultiply-12 1000000000 0.0000027 ns/op
BenchmarkBigintFloatMultiply
BenchmarkBigintFloatMultiply-12 1000000000 0.0000028 ns/op
BenchmarkBiggerFloatDivide
BenchmarkBiggerFloatDivide-12 1000000000 0.0000026 ns/op
BenchmarkBigintFloatDivide
BenchmarkBigintFloatDivide-12 1000000000 0.0000025 ns/op
PASS
4.3 结论:
以下使用benchmark测试其性能,观察发现,BigInteger中,math/big的性能会更加优一点,但是相差无几,在1.5倍差距左右。在浮点数计算中,性能完全一致,有时更优。
5.go中NewFloat精度问题
在go中math下的big包中,NewFloat实际上存在精度问题,如下代码:
得出的结果为0.8999999999999999。这明显是浮点数计算导致的问题。我设计的bigger包中不存在此类问题。
func main() {
a := big.NewFloat(0.2)
b := big.NewFloat(0.7)
res := a.Add(a, b)
fmt.Println(res) //0.8999999999999999
}
如下代码,为bigger包中bigDecimal所得出的结果:
func main() {
a := bigger.NewBigDecimalString("0.2")
b := bigger.NewBigDecimalString("0.7")
res := a.Add(b)
res = res.SetScale(12, bigger.ROUND_HALF_UP)
fmt.Println(res.String()) // 0.900000000000
}