不能用 float64/int64 或 strconv.parseint 处理超长整数,因溢出或精度丢失;须用 big.int 的 setstring(需指定进制并检查 ok)、add/sub/mul(就地修改)、text(10) 输出完整十进制字符串。

直接用 float64 或 int64 存超长整数,结果必然错——不是溢出就是精度丢失,根本没法用。
为什么不能用 strconv.ParseInt 解析几百位的数字
因为 strconv.ParseInt 第三个参数是 bit size(如 64),它最终还是要塞进 int64;一旦字符串表示的数超过 9223372036854775807,就会返回 strconv.ParseInt: parsing "...": value out of range 错误。
- 哪怕你传
128当 size,也无效——Go 没有int128类型,该函数只支持 ≤64 的值 -
strconv.Atoi更危险,它底层调的是ParseInt(s, 10, 0),0 表示“用平台默认 int”,照样崩 - 所有这类函数都属于「把大数往小容器里硬塞」,失败是设计使然,不是配置问题
SetString 必须指定进制且检查返回值
SetString 看似简单,但漏掉进制或忽略 ok 返回值,会导致静默失败:变量保持零值,后续计算全错,还不报 panic。
- 十进制字符串(如
"12345678901234567890")必须传10:a.SetString(s, 10) - 十六进制(如
"ff")要先去掉"0x"前缀,再传16;传10会当成一百一十一 - 字符串首尾有空格、换行符(比如从 JSON 或文件读来)会直接失败,建议先
strings.TrimSpace(s) - 务必检查第二个返回值:
if _, ok := a.SetString(s, 10); !ok { /* 处理错误 */ }
Add / Sub / Mul 都是就地修改,别误以为返回新对象
写 c.Add(a, b) 是把 a + b 的结果写进 c;而写 a.Add(a, b) 是直接改掉 a 本身——这是最常踩的坑,尤其在循环或复用变量时。
- 想保留
a和b原值?得显式新建:c := new(big.Int).Add(a, b) - 想链式调用又不污染原值?用
new(big.Int).Set(a).Add(new(big.Int), b),但注意中间new(big.Int)也要接上 - 没有「不可变 big.Int」,也没有
Clone()方法;Set()是浅拷贝,但对用户来说足够安全 - 高频场景(如密码学循环)中反复
new(big.Int)会增加 GC 压力,建议复用变量或配sync.Pool
输出时避免 fmt.Println 隐式调用 String() 导致科学计数法
fmt.Println(sum) 实际调用的是 sum.String(),而 String() 对极大数可能返回科学计数法形式(如 1.23e+100),这不是 bug,是设计行为。你需要的是纯十进制字符串。
- 一律用
sum.Text(10)获取无格式十进制字符串 -
Text(10)的参数是 base,不是小数位数;它保证输出完整数字,不含 e - 如果要转成
[]byte,用sum.Bytes(),但注意它是大端二进制编码,不是 ASCII 字符串 - JSON 序列化需手动包装:直接
json.Marshal(&bigInt)得到{},必须实现MarshalJSON返回"123..."
真正麻烦的从来不是「怎么加」,而是「谁被改了」「错在哪一行没检查 ok」「输出看着像数其实不是人能读的字符串」——这些细节不盯死,跑通一次也迟早翻车。











