Go中高精度浮点计算唯一标准库方案是math/big的big.Float,但需全程手动对齐精度:必须用SetString初始化、显式设置prec(二进制位数)、运算前确保操作数精度一致、避免混用float64、比较用Cmp而非==。

Go 里想做真正高精度浮点计算,math/big 的 big.Float 是唯一标准库方案,但它不等于“把 float64 换成 big.Float 就自动高精度”——原始输入、精度设置、运算链路全得手动对齐,漏一环就退回 float64 精度。
big.Float 必须用 SetString 初始化,否则精度从源头就废了
很多人写 new(big.Float).SetFloat64(0.1 + 0.2),结果还是 0.30000000000000004。这不是 big.Float 的问题,而是 0.1 和 0.2 在 float64 里本就无法精确表示,传进去的已经是失真值。
-
SetString("0.1")才是正确入口:它按十进制字面量直接解析,跳过二进制浮点转换 - 返回值是
(*big.Float, bool),第二个布尔值必须检查,失败说明字符串格式非法(比如含空格、逗号、"1,000.0") - 支持科学计数法:
"1.23e-5"、"4.5E+2"都可以,但不支持千分位或单位符号
prec 控制的是二进制位数,不是小数位数
big.Float 的 prec 参数单位是 bit(二进制有效位),不是你想要的“保留 10 位小数”。设 prec = 64 ≈ 19 位十进制有效数字,和 float64 默认精度差不多;要算 100 位十进制精度,得设 prec = 333(≈ log₂(10¹⁰⁰))。
- 构造时显式调用
SetPrec():例如new(big.Float).SetPrec(256) - 运算结果精度取操作数中最高
prec,所以两个big.Float相加前,得确保它们都设了足够精度,否则低精度 operand 会拖垮整体 - 输出格式和内部精度无关:
f.Text('f', 20)只控制显示,不提升实际精度;补再多小数位,底层仍是 64-bit 有效数字
Quo 除法必须传两个 *big.Float,且需防零除
big.Float 没有 Div 方法,Div 属于 big.Int;除法必须用 Quo(z, x, y) 或接收者调用 z.Quo(x, y),且 x 和 y 都得是 *big.Float。
立即学习“go语言免费学习笔记(深入)”;
-
big.Int转big.Float不能隐式转换:要用new(big.Float).SetInt(i),且记得先设SetPrec() -
y为零时,Quo返回 ±Inf 或 NaN,生产代码应加y.Sign() != 0校验 - 避免频繁 new:循环里复用
term := new(big.Float),每次用前调term.SetPrec(prec)重置精度
别混用 big.Float 和 float64,也别信 == 比较
一旦混入 float64,整个高精度链就断了。比如 big.Float.Add(f, big.NewFloat(1.0)),那个 1.0 是 float64 字面量,已带误差;更糟的是 big.Float.SetFloat64(x),x 本身可能就是计算产物。
- 所有输入源——用户输入、配置、API 返回——优先走字符串路径,再
SetString -
big.Float之间比较不能用==,得用f.Cmp(g) == 0;涉及 float64 时,用误差范围判断:math.Abs(f.Float64() - g) (注意 <code>Float64()会丢失精度,仅作近似参考) - 并发场景下,
big.Float非线程安全,多个 goroutine 同时调Add或Set会数据竞争,必须加锁或用局部变量
真正难的不是调哪个方法,而是整条数据流——从输入、中间运算到输出——每个环节都得主动扛起精度责任。字符串进、prec 对齐、Quo 显式、比较用 Cmp,漏掉任意一环,高精度就只是幻觉。


















