big.NewFloat 不能直接传 float64 字面量(如 big.NewFloat(1.23)),因其会继承 float64 的二进制表示失真;正确做法是先 SetPrec 再 SetString("1.23"),确保十进制字面量无损解析。

big.NewFloat 为什么不能直接用
直接调用 big.NewFloat(1.23) 看似简单,但结果可能和你预期的完全不一样——它把 1.23 当作 float64 字面量传入,而 float64 本身在二进制中就无法精确表示十进制小数。比如 big.NewFloat(0.1).Add(..., big.NewFloat(0.2)) 最终还是得到 0.30000000000000004。
这不是 big.Float 的 bug,而是输入源已失真。高精度的前提是“源头干净”,必须绕过 float64 这一关。
- ✅ 正确做法:用
SetString("1.23"),从字符串字面量解析十进制值 - ❌ 错误写法:
big.NewFloat(1.23)、new(big.Float).SetFloat64(1.23) - ⚠️ 注意:
SetString返回(*big.Float, bool),第二个布尔值必须检查,失败时返回nil - 支持科学计数法:
"1.23e-5"、"4.5E+2"合法;"1,000.0"或带空格的字符串会失败
SetPrec 必须在 SetString 前还是后
顺序错了,精度就白设了。必须先调 SetPrec,再调 SetString。因为 SetString 解析时会根据当前精度做舍入——如果没设精度,big.Float 默认 prec = 0,解析结果直接变成 0 或 NaN。
- ✅ 正确顺序:
new(big.Float).SetPrec(256).SetString("3.14159265358979323846") - ❌ 反过来:
new(big.Float).SetString("3.14...").SetPrec(256)—— 此时数值已按默认精度(约 19 位十进制)截断,再设高精度也救不回来 - ? prec 单位是二进制位:256 bit ≈ 77 位十进制有效数字;想输出 50 位小数,建议设
prec ≥ 192
为什么 new(big.Float) 创建后不能直接用 Quo 或 Add
new(big.Float) 返回的是零值指针,其内部 prec 为 0,mant(尾数)为空切片。此时任何运算如 Quo、Add 都会静默失败或返回 NaN,不会 panic,但结果不可信。
立即学习“go语言免费学习笔记(深入)”;
- ✅ 安全写法:
f := new(big.Float).SetPrec(256),显式初始化精度后再参与运算 - ❌ 危险写法:
f := new(big.Float); f.Quo(x, y)—— 即使x和y都设了精度,f自身仍是无效状态 - ? 所有接收者(左值)都必须已设置
prec;运算结果精度取操作数中最高prec,但接收者自身精度不足会拖垮整体 - 复用变量更高效:
quo := new(big.Float).SetPrec(256),循环中反复调quo.Quo(a, b)
如何安全地把 big.Int 转成 big.Float
不能直接赋值,也不能靠 Float64() 中转——后者只返回最接近的 float64,大整数一转就丢精度。关键看目标值是否在 big.Float 的指数范围内,且能否被当前精度精确表示。
- ✅ 安全路径:
new(big.Float).SetPrec(p).SetInt(i),其中i是*big.Int,p是足够大的精度 - ⚠️ 溢出风险:若
i.BitLen() > p,SetInt可能返回+Inf;建议先用i.BitLen()估算所需最小prec - ❌ 绝对避免:
new(big.Float).SetFloat64(i.Float64())—— 超过2^53的整数,Float64()就开始丢位 - 字符串中转兜底:
new(big.Float).SetPrec(p).SetString(i.Text(10)),适用于任意大小,但稍慢
big.Float 实例都得亲手确认 prec 已设、SetString 在 SetPrec 之后、接收者非零值且已初始化。漏掉任一环,高精度就退化成普通浮点。


















