在日常的开发过程中,不可避免的需要使用到超过变量类型的数值计算,在 go 语言中,int64 类型的变量的储存范围是
-9223372036854775808 ~ 9223372036854775807,当我们需要计算的数值大于这个范围之后,计算出的结果就会出错,这时候就需要使用到
go 语言中专门为大数计算而存在的标准库:math/big 包里面的内容。

比如


package main

import (
	"fmt"
	"math"
)

func main() {
	a := math.MaxInt64
	b := math.MaxInt64
	c := a + b
	fmt.Printf("%d + %d = %d", a, b, c)
}

可以看出两个最大值的相加结果异常,这是因为两个最大值相加的结果超出了 int64 能够存储的范围。

math/big

如果需要进行上面这样的大数计算,可以使用 go 语言自带的 math/big 包进行计算,big 包中包含了整形 int 和浮点型 float 的大数计算。

package main

import (
	"fmt"
	"math"
	"math/big"
)

func main() {
	a := big.NewInt(math.MaxInt64)
	b := big.NewInt(math.MaxInt64)
	result := a.Add(a, b)
	fmt.Println(result)

}

这样就可以相加了!

从字符串生成超大数字

package main

import (
	"fmt"
	"math/big"
)

func main() {
	a := big.NewInt(1)
	big1, ok := a.SetString("23431241234123412341324123412341234123434123432431241234132412341234123431241234", 10)
	if !ok {
		fmt.Println("设置失败")
	}
	fmt.Println(big1)

}

浮点数

大有理数 big.Rat 类型

大有理数的 big.Rat 类型

big.Rat 是Go语言 math/big 包中的一个类型,用于表示任意精度的有理数(即分数形式的数,如 ab\frac{a}{b},其中 aa 是分子,bb 是非零分母)。以下从多个方面对其进行介绍:

1. 创建 big.Rat 对象

  • 使用 big.NewRat 函数
    该函数接受两个 int64 类型的参数,分别为分子和分母,返回一个指向 big.Rat 对象的指针。例如:
package main

import (
    "fmt"
    "math/big"
)

func main() {
    rat := big.NewRat(3, 4)
    fmt.Println(rat)
}

此代码创建了有理数 34\frac{3}{4} 并输出。

  • 使用 SetFrac 方法
    该方法可用于设置 big.Rat 对象的分子和分母,接受两个 big.Int 类型的参数。这在处理大整数作为分子或分母时非常有用。例如:
package main

import (
    "fmt"
    "math/big"
)

func main() {
    num := big.NewInt(12345678901234567890)
    den := big.NewInt(98765432109876543210)
    rat := new(big.Rat).SetFrac(num, den)
    fmt.Println(rat)
}

2. 约分

big.Rat 对象在创建时会自动进行约分。例如,创建 68\frac{6}{8} 时,实际存储的是约分后的 34\frac{3}{4}。这确保了有理数以最简形式表示,方便后续计算和比较。

3. 基本运算

  • 加法:使用 Add 方法,将两个 big.Rat 对象相加。例如:
package main

import (
    "fmt"
    "math/big"
)

func main() {
    rat1 := big.NewRat(1, 2)
    rat2 := big.NewRat(1, 3)
    result := new(big.Rat).Add(rat1, rat2)
    fmt.Println(result)
}

这里计算 12+13=56\frac{1}{2} + \frac{1}{3} = \frac{5}{6}

  • 减法:通过 Sub 方法实现。例如:
package main

import (
    "fmt"
    "math/big"
)

func main() {
    rat1 := big.NewRat(3, 4)
    rat2 := big.NewRat(1, 4)
    result := new(big.Rat).Sub(rat1, rat2)
    fmt.Println(result)
}

3414=24=12\frac{3}{4}-\frac{1}{4}=\frac{2}{4}=\frac{1}{2}(自动约分)。

  • 乘法:使用 Mul 方法。例如:
package main

import (
    "fmt"
    "math/big"
)

func main() {
    rat1 := big.NewRat(2, 3)
    rat2 := big.NewRat(3, 5)
    result := new(big.Rat).Mul(rat1, rat2)
    fmt.Println(result)
}

计算 23×35=25\frac{2}{3}×\frac{3}{5}=\frac{2}{5}

  • 除法:通过 Quo 方法进行。例如:
package main

import (
    "fmt"
    "math/big"
)

func main() {
    rat1 := big.NewRat(4, 5)
    rat2 := big.NewRat(2, 3)
    result := new(big.Rat).Quo(rat1, rat2)
    fmt.Println(result)
}

45÷23=45×32=65\frac{4}{5}÷\frac{2}{3}=\frac{4}{5}×\frac{3}{2}=\frac{6}{5}

4. 比较

  • Cmp 方法:用于比较两个 big.Rat 对象的大小。返回值为 -1(表示第一个数小于第二个数)、0(表示两个数相等)或 1(表示第一个数大于第二个数)。例如:
package main

import (
    "fmt"
    "math/big"
)

func main() {
    rat1 := big.NewRat(1, 2)
    rat2 := big.NewRat(3, 4)
    cmp := rat1.Cmp(rat2)
    if cmp == -1 {
        fmt.Println("rat1 小于 rat2")
    } else if cmp == 0 {
        fmt.Println("rat1 等于 rat2")
    } else {
        fmt.Println("rat1 大于 rat2")
    }
}

5. 转换

  • 转换为浮点数Float64 方法将 big.Rat 对象转换为 float64 类型的值。需要注意的是,由于 float64 精度有限,可能会丢失精度。例如:
package main

import (
    "fmt"
    "math/big"
)

func main() {
    rat := big.NewRat(1, 3)
    f := rat.Float64()
    fmt.Printf("%.10f\n", f)
}

这里将 13\frac{1}{3} 转换为 float64,输出结果会有一定精度损失。

  • 转换为字符串String 方法将 big.Rat 对象转换为字符串形式,格式为 分子/分母。例如:
package main

import (
	"fmt"
	"math/big"
)

func main() {
	rat := big.NewRat(5, 7)
	s := rat.String()
	fmt.Println(s)
}

big.Rat 类型在需要精确表示和计算有理数的场景中非常有用,如金融计算、科学计算等领域,避免了浮点数运算可能带来的精度问题。