Golang中big.Rat和big.Int的详细函数调用解析
Golang中big.Rat和big.Int的详细函数调用解析
math/big 包提供了处理任意精度整数和有理数的类型与函数。我想知道是否有人了解为何这些函数调用如此冗长多余。例如查看两个有理数相乘的文档:https://golang.org/pkg/math/big/#Rat.Mul
必须提供两个参数进行相乘,然后将结果写入接收器,而不是让接收器直接与单个参数相乘。为何要这样设计?
你可能在事后需要两个输入值,因此需要提供能够存储结果的内存区域。但如果之后不需要这些结果,你可以使用其内存区域来存储结果,这样就能有效选择在可能的情况下避免巨大的内存分配。
更多关于Golang中big.Rat和big.Int的详细函数调用解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这是一个合理的观点。虽然不完全符合我的风格,但现在我可以接受我的代码保持现在的样子了。
rat := (&big.Rat{}).Mul(big.NewRat(tickCount, tickFrequency), big.NewRat(1000000, 1))
microsPassed := (&big.Int{}).Div(rat.Num(), rat.Denom()).Int64()
谢谢。
math/big 包中 Rat 和 Int 类型采用这种显式操作模式,主要是为了优化性能并减少内存分配。通过复用现有的 big.Rat 或 big.Int 对象作为结果容器,可以避免在频繁运算中创建新对象带来的开销。这种设计在需要执行大量大数运算的场景下尤为重要。
以下是一个对比示例,展示直接使用接收器与复用对象的区别:
传统方式(每次创建新对象):
// 每次运算都返回新对象,导致额外分配
result := new(big.Rat).Mul(a, b)
实际 math/big 的方式(复用对象):
package main
import (
"fmt"
"math/big"
)
func main() {
// 初始化两个有理数
a := big.NewRat(3, 4) // 3/4
b := big.NewRat(2, 5) // 2/5
result := new(big.Rat) // 预分配结果对象
// 复用 result 存储乘法结果
result.Mul(a, b)
fmt.Printf("%v * %v = %v\n", a, b, result) // 输出: 3/4 * 2/5 = 3/10
// 继续使用 result 进行其他运算
c := big.NewRat(1, 2)
result.Mul(result, c)
fmt.Printf("再乘以 %v = %v\n", c, result) // 输出: 再乘以 1/2 = 3/20
}
这种设计允许链式操作和结果复用:
x, y, z := big.NewRat(1, 2), big.NewRat(3, 4), big.NewRat(5, 6)
tmp := new(big.Rat)
tmp.Mul(x, y).Add(tmp, z) // 链式操作: (x * y) + z
对于 big.Int 也是同样的模式:
a := big.NewInt(100)
b := big.NewInt(50)
sum := new(big.Int)
sum.Add(a, b) // sum = a + b
这种 API 设计虽然看起来冗长,但在处理大规模数值计算时能显著提升性能,因为它避免了不必要的内存分配和垃圾回收压力。

