Golang中big.Rat和big.Int的详细函数调用解析

Golang中big.Rat和big.Int的详细函数调用解析 math/big 包提供了处理任意精度整数和有理数的类型与函数。我想知道是否有人了解为何这些函数调用如此冗长多余。例如查看两个有理数相乘的文档:https://golang.org/pkg/math/big/#Rat.Mul

必须提供两个参数进行相乘,然后将结果写入接收器,而不是让接收器直接与单个参数相乘。为何要这样设计?

3 回复

你可能在事后需要两个输入值,因此需要提供能够存储结果的内存区域。但如果之后不需要这些结果,你可以使用其内存区域来存储结果,这样就能有效选择在可能的情况下避免巨大的内存分配。

更多关于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 包中 RatInt 类型采用这种显式操作模式,主要是为了优化性能并减少内存分配。通过复用现有的 big.Ratbig.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 设计虽然看起来冗长,但在处理大规模数值计算时能显著提升性能,因为它避免了不必要的内存分配和垃圾回收压力。

回到顶部