在日常的开发过程中,不可避免的需要使用到超过变量类型的数值计算,在 go 语言中,int64 类型的变量的储存范围是
-9223372036854775808 ~ 9223372036854775807,当我们需要计算的数值大于这个范围之后,计算出的结果就会出错,这时候就需要使用到
go 语言中专门为大数计算而存在的标准库:math/big 包里面的内容。
比如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 的大数计算。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 )
}
这样就可以相加了!
从字符串生成超大数字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
包中的一个类型,用于表示任意精度的有理数(即分数形式的数,如 $\frac{a}{b}$,其中 $a$ 是分子,$b$ 是非零分母)。以下从多个方面对其进行介绍:
1. 创建 big.Rat
对象
使用 big.NewRat
函数 :
该函数接受两个 int64
类型的参数,分别为分子和分母,返回一个指向 big.Rat
对象的指针。例如:
1
2
3
4
5
6
7
8
9
10
11
package main
import (
"fmt"
"math/big"
)
func main () {
rat := big . NewRat ( 3 , 4 )
fmt . Println ( rat )
}
此代码创建了有理数 $\frac{3}{4}$ 并输出。
使用 SetFrac
方法 :
该方法可用于设置 big.Rat
对象的分子和分母,接受两个 big.Int
类型的参数。这在处理大整数作为分子或分母时非常有用。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
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
对象在创建时会自动进行约分。例如,创建 $\frac{6}{8}$ 时,实际存储的是约分后的 $\frac{3}{4}$。这确保了有理数以最简形式表示,方便后续计算和比较。
3. 基本运算
加法 :使用 Add
方法,将两个 big.Rat
对象相加。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
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 )
}
这里计算 $\frac{1}{2} + \frac{1}{3} = \frac{5}{6}$。
1
2
3
4
5
6
7
8
9
10
11
12
13
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 )
}
即 $\frac{3}{4}-\frac{1}{4}=\frac{2}{4}=\frac{1}{2}$(自动约分)。
1
2
3
4
5
6
7
8
9
10
11
12
13
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 )
}
计算 $\frac{2}{3}×\frac{3}{5}=\frac{2}{5}$。
1
2
3
4
5
6
7
8
9
10
11
12
13
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 )
}
即 $\frac{4}{5}÷\frac{2}{3}=\frac{4}{5}×\frac{3}{2}=\frac{6}{5}$。
4. 比较
Cmp
方法 :用于比较两个 big.Rat
对象的大小。返回值为 -1
(表示第一个数小于第二个数)、0
(表示两个数相等)或 1
(表示第一个数大于第二个数)。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
精度有限,可能会丢失精度。例如:
1
2
3
4
5
6
7
8
9
10
11
12
package main
import (
"fmt"
"math/big"
)
func main () {
rat := big . NewRat ( 1 , 3 )
f := rat . Float64 ()
fmt . Printf ( "%.10f\n" , f )
}
这里将 $\frac{1}{3}$ 转换为 float64
,输出结果会有一定精度损失。
转换为字符串 :String
方法将 big.Rat
对象转换为字符串形式,格式为 分子/分母
。例如:
1
2
3
4
5
6
7
8
9
10
11
12
package main
import (
"fmt"
"math/big"
)
func main () {
rat := big . NewRat ( 5 , 7 )
s := rat . String ()
fmt . Println ( s )
}
big.Rat
类型在需要精确表示和计算有理数的场景中非常有用,如金融计算、科学计算等领域,避免了浮点数运算可能带来的精度问题。