
math/big.Int 不能直接用 + - * / 运算符
Go 的 math/big 类型是值语义的结构体,不是基础类型,所有算术操作必须调用方法,否则编译报错或结果意外。比如 a + b 会提示 invalid operation: a + b (operator + not defined on *big.Int)。
- 所有计算都得用
Int.Add()、Int.Mul()、Int.Sub()、Int.Div()等方法,且第一个参数是接收者(即目标变量),第二个才是操作数 - 多数方法返回接收者本身(链式调用可行),但注意它们是**就地修改**——
a.Add(a, b)会改掉a原值,别误以为是“返回新对象” - 如果需要保留原值,得先用
new(big.Int).Set(a)拷贝,big.Int没有内置克隆方法 - 除法
Div()默认向零截断,不支持取模和整除分离;要余数得用QuoRem()
从字符串初始化 big.Int 容易忽略进制和空格
用 SetString() 解析大数时,默认按十进制,但若字符串带前缀(如 "0x1F")或含空格、换行,会静默失败并返回 nil,且不报错——只通过第二个返回值 ok bool 判断是否成功。
- 十六进制必须显式传入
0作为 base 参数:i.SetString("1a2b", 16),"0x1a2b"要先去掉前缀 - 字符串首尾空白(包括
\n)会导致解析失败,建议先strings.TrimSpace() - 负数字符串如
"-999999999999999999999"是合法的,但"- 999"(中间有空格)不行 - 避免用
fmt.Sscanf或strconv.ParseInt中转,它们无法处理超int64范围的字面量
big.Float 精度控制不等于浮点数“四舍五入”
big.Float 的精度由 Accuracy(单位是二进制位)决定,不是小数点后几位。设成 10 并不意味着保留 10 位小数,而是约等于 3 位十进制有效数字(因 log₁₀(2¹⁰) ≈ 3.01)。
- 初始化时务必指定精度:
new(big.Float).SetPrec(53)(模拟 float64)或更高;默认精度是 0,行为未定义 - 输出为字符串时,
Text('g', 10)的第二个参数是**最大有效数字位数**,不是小数位数;要固定小数位得用Format配合math/big外部四舍五入逻辑 -
big.Float的Add/Mul等方法也会受当前精度影响,多次运算后误差可能累积,别默认它“绝对精确” - 比较两个
big.Float是否相等,不能用==,要用Cmp(),因为底层是近似表示
性能敏感场景下避免频繁分配 big.Int 临时对象
每次调用 new(big.Int) 或 big.NewInt(0) 都会分配堆内存。在循环或高频计算中,反复创建销毁 *big.Int 会触发 GC 压力,实测比复用对象慢 3–5 倍。
立即学习“go语言免费学习笔记(深入)”;
- 把常用临时变量声明为局部变量或结构体字段,重复调用
SetInt64(0)或Set(nil)重置即可 - 可预先准备一个
sync.Pool存*big.Int,但注意big.Int内部缓冲区不会自动清零,取出后必须SetInt64(0)或Set(nil) -
big.Int的Bytes()返回的是内部字节数组切片,别长期持有——下次写入可能被覆盖;需拷贝用append([]byte{}, i.Bytes()...) - 如果只是做一次简单幂运算(如 RSA 模幂),优先用
Exp(x, y, m),它内部已优化内存复用,别手动拆成多个Mul+Mod
实际用起来最常卡住的地方,是习惯性写 a + b 或漏判 SetString() 的返回值 ok;还有人以为 big.Float 设了精度就能当高精度小数用,结果发现 0.1 + 0.2 != 0.3 ——它还是二进制浮点,只是位数可调。










