big.Float的SetPrec单位是二进制位(bits),非十进制小数位;如SetPrec(53)≈15.95位十进制有效数字,SetPrec(256)≈77位,必须显式设置且不可恢复已丢失精度。

math/big 包本身不提供“精度控制”这个概念——它对 big.Int 是无精度损失的整数运算,而对 big.Float 才真正涉及精度(prec)和舍入模式(mode)。很多人误以为 big.Int 也能设精度,其实那是混淆了类型语义。
big.Float 的 SetPrec 是什么单位?
SetPrec 设置的是二进制有效位数(bits),不是十进制小数位。
比如:
-
SetPrec(53)≈ float64 精度(log₁₀(2⁵³) ≈ 15.95 位十进制有效数字) -
SetPrec(256)≈ 77 位十进制有效数字,适合高精度金融或密码学计算 -
SetPrec(10)只有约 3 位十进制有效数字,极易误判为“高精度”
常见错误:
- 忘记调用
SetPrec,用默认值 0 → 行为未定义,可能 panic 或返回空字符串 - 用
Text('g', 20)想输出 20 位小数 → 实际受限于内部 prec,补再多格式位也没用
必须显式初始化:
var f *big.Float = new(big.Float).SetPrec(256).SetString("3.14159265358979323846")为什么不能用 float64 直接构造 big.Float?
SetFloat64(0.1) 会把 IEEE 754 的二进制近似值(0.10000000000000000555…)原样塞进去,误差已存在,大数库救不回来。
立即学习“go语言免费学习笔记(深入)”;
正确做法始终优先走字符串:
- ✅
new(big.Float).SetPrec(256).SetString("0.1", 10) - ❌
new(big.Float).SetPrec(256).SetFloat64(0.1)
同理,从 JSON、用户输入、配置文件读到的数字,一律用 SetString,别经由 strconv.ParseFloat 中转。
big.Int 没有精度,但有“表示安全边界”
big.Int 是精确整数,不谈精度,但有三个关键边界需手动把关:
- 初始化超大字面量时:
big.NewInt(12345678901234567890)会静默截断(因参数是int64)→ 改用new(big.Int).SetString("12345678901234567890", 10) - 转回原生类型时:
x.Int64()或x.Uint64()可能溢出 → 先用x.BitLen()判断位宽,或检查x.Sign() == 0和范围 - 序列化到 JSON 时:
big.Int不实现json.Marshaler→ 直接json.Marshal得{},必须包装结构体并手动实现MarshalJSON返回字符串
最易被忽略的一点:big.Float 的精度是每个实例独立携带的,不是全局设置;两个 big.Float 运算时,结果精度取二者中较小者,不会自动提升。如果中间某步用了低 prec 实例,后续再怎么 SetPrec 都无法恢复丢失的位数。


















